ELf32::unpack; Elf64 parity with Elf32 for shlib with no DT_INIT
https://github.com/upx/upx/issues/191 [partial, not finished] modified: p_lx_elf.cpp
This commit is contained in:
parent
5e9b6bd69d
commit
f1a31b4793
109
src/p_lx_elf.cpp
109
src/p_lx_elf.cpp
@ -431,7 +431,7 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
|||||||
}
|
}
|
||||||
off += (align-1) & (ioff - off);
|
off += (align-1) & (ioff - off);
|
||||||
fo->seek( off, SEEK_SET);
|
fo->seek( off, SEEK_SET);
|
||||||
fo->write(ioff + file_image, len);
|
fo->write(&file_image[ioff], len);
|
||||||
so_slide = off - ioff;
|
so_slide = off - ioff;
|
||||||
set_te32(&phdr->p_offset, so_slide + ioff);
|
set_te32(&phdr->p_offset, so_slide + ioff);
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
|||||||
|
|
||||||
off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
||||||
{
|
{
|
||||||
unsigned flen = super::pack3(fo, ft); // loader follows compressed PT_LOADs
|
off_t flen = super::pack3(fo, ft); // loader follows compressed PT_LOADs
|
||||||
// NOTE: PackLinuxElf::pack3 adjusted xct_off for the extra page
|
// NOTE: PackLinuxElf::pack3 adjusted xct_off for the extra page
|
||||||
|
|
||||||
unsigned v_hole = sz_pack2 + lsize;
|
unsigned v_hole = sz_pack2 + lsize;
|
||||||
@ -525,11 +525,12 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
set_te32(&elfout.phdr[1].p_flags, Elf32_Phdr::PF_W|Elf32_Phdr::PF_R);
|
set_te32(&elfout.phdr[1].p_flags, Elf32_Phdr::PF_W|Elf32_Phdr::PF_R);
|
||||||
}
|
}
|
||||||
if (0!=xct_off) { // shared library
|
if (0!=xct_off) { // shared library
|
||||||
|
upx_uint64_t word = load_va + sz_pack2;
|
||||||
|
set_te64(&file_image[user_init_off], word); // set the hook
|
||||||
|
|
||||||
Elf64_Phdr *phdr = (Elf64_Phdr *)lowmem.subref(
|
Elf64_Phdr *phdr = (Elf64_Phdr *)lowmem.subref(
|
||||||
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr));
|
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr));
|
||||||
unsigned off = fo->st_size();
|
unsigned off = fo->st_size();
|
||||||
unsigned off_init = 0; // where in file
|
|
||||||
upx_uint64_t va_init = sz_pack2; // virtual address
|
|
||||||
so_slide = 0;
|
so_slide = 0;
|
||||||
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
||||||
upx_uint64_t const len = get_te64(&phdr->p_filesz);
|
upx_uint64_t const len = get_te64(&phdr->p_filesz);
|
||||||
@ -564,36 +565,15 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
set_te64(&phdr->p_offset, so_slide + ioff);
|
set_te64(&phdr->p_offset, so_slide + ioff);
|
||||||
}
|
}
|
||||||
else { // Change length of first PT_LOAD.
|
else { // Change length of first PT_LOAD.
|
||||||
va_init += get_te64(&phdr->p_vaddr);
|
|
||||||
set_te64(&phdr->p_filesz, sz_pack2 + lsize);
|
set_te64(&phdr->p_filesz, sz_pack2 + lsize);
|
||||||
set_te64(&phdr->p_memsz, sz_pack2 + lsize);
|
set_te64(&phdr->p_memsz, sz_pack2 + lsize);
|
||||||
}
|
}
|
||||||
continue; // all done with this PT_LOAD
|
continue; // all done with this PT_LOAD
|
||||||
}
|
}
|
||||||
// Compute new offset of &DT_INIT.d_val.
|
|
||||||
if (Elf64_Phdr::PT_DYNAMIC==type) {
|
|
||||||
off_init = ioff + ((xct_off < ioff) ? so_slide : 0);
|
|
||||||
Elf64_Dyn *dyn = (Elf64_Dyn *)&file_image[ioff];
|
|
||||||
for (int j2 = len; j2 > 0; ++dyn, j2 -= sizeof(*dyn)) {
|
|
||||||
if (upx_dt_init==get_te64(&dyn->d_tag)) {
|
|
||||||
unsigned const t = (unsigned char *)&dyn->d_val -
|
|
||||||
(unsigned char *)&file_image[ioff];
|
|
||||||
off_init += t;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fall through to relocate .p_offset
|
|
||||||
}
|
|
||||||
if (xct_off < ioff)
|
if (xct_off < ioff)
|
||||||
set_te64(&phdr->p_offset, so_slide + ioff);
|
set_te64(&phdr->p_offset, so_slide + ioff);
|
||||||
} // end each Phdr
|
} // end each Phdr
|
||||||
|
|
||||||
if (off_init) { // change DT_INIT.d_val
|
|
||||||
fo->seek(off_init, SEEK_SET);
|
|
||||||
upx_uint64_t word; set_te64(&word, va_init);
|
|
||||||
fo->rewrite(&word, sizeof(word));
|
|
||||||
flen = fo->seek(0, SEEK_END);
|
|
||||||
}
|
|
||||||
if (opt->o_unix.android_shlib) {
|
if (opt->o_unix.android_shlib) {
|
||||||
// Update {DYNAMIC}.sh_offset by so_slide.
|
// Update {DYNAMIC}.sh_offset by so_slide.
|
||||||
Elf64_Shdr *shdr = (Elf64_Shdr *)lowmem.subref(
|
Elf64_Shdr *shdr = (Elf64_Shdr *)lowmem.subref(
|
||||||
@ -1715,7 +1695,7 @@ bool PackLinuxElf32::canPack()
|
|||||||
note_size = 0;
|
note_size = 0;
|
||||||
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
||||||
if (j >= 14) {
|
if (j >= 14) {
|
||||||
throwCantPack("too many Elf32_Phdr; try '--force-execve'");
|
throwCantPack("too many ElfXX_Phdr; try '--force-execve'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
unsigned const p_type = get_te32(&phdr->p_type);
|
unsigned const p_type = get_te32(&phdr->p_type);
|
||||||
@ -1814,8 +1794,6 @@ bool PackLinuxElf32::canPack()
|
|||||||
if (sec_dynsym)
|
if (sec_dynsym)
|
||||||
sec_dynstr = get_te32(&sec_dynsym->sh_link) + shdri;
|
sec_dynstr = get_te32(&sec_dynsym->sh_link) + shdri;
|
||||||
|
|
||||||
sec_strndx = &shdri[get_te16(&ehdr->e_shstrndx)];
|
|
||||||
shstrtab = (char const *)(get_te32(&sec_strndx->sh_offset) + file_image);
|
|
||||||
if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|
if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|
||||||
|| 0!=strcmp((char const *)".shstrtab",
|
|| 0!=strcmp((char const *)".shstrtab",
|
||||||
&shstrtab[get_te32(&sec_strndx->sh_name)]) ) {
|
&shstrtab[get_te32(&sec_strndx->sh_name)]) ) {
|
||||||
@ -1961,8 +1939,8 @@ proceed: ;
|
|||||||
if (!super::canPack())
|
if (!super::canPack())
|
||||||
return false;
|
return false;
|
||||||
assert(exetype == 1);
|
assert(exetype == 1);
|
||||||
|
|
||||||
exetype = 0;
|
exetype = 0;
|
||||||
|
|
||||||
// set options
|
// set options
|
||||||
opt->o_unix.blocksize = blocksize = file_size;
|
opt->o_unix.blocksize = blocksize = file_size;
|
||||||
return true;
|
return true;
|
||||||
@ -1998,8 +1976,10 @@ PackLinuxElf64::canPack()
|
|||||||
// The first PT_LOAD64 must cover the beginning of the file (0==p_offset).
|
// The first PT_LOAD64 must cover the beginning of the file (0==p_offset).
|
||||||
Elf64_Phdr const *phdr = phdri;
|
Elf64_Phdr const *phdr = phdri;
|
||||||
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
||||||
if (j >= 14)
|
if (j >= 14) {
|
||||||
|
throwCantPack("too many ElfXX_Phdr; try '--force-execve'");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
unsigned const p_type = get_te32(&phdr->p_type);
|
unsigned const p_type = get_te32(&phdr->p_type);
|
||||||
if (1!=exetype && PT_LOAD64 == p_type) { // 1st PT_LOAD
|
if (1!=exetype && PT_LOAD64 == p_type) { // 1st PT_LOAD
|
||||||
exetype = 1;
|
exetype = 1;
|
||||||
@ -2095,8 +2075,34 @@ PackLinuxElf64::canPack()
|
|||||||
xct_va = ~0ull;
|
xct_va = ~0ull;
|
||||||
if (e_shnum) {
|
if (e_shnum) {
|
||||||
for (int j= e_shnum; --j>=0; ++shdr) {
|
for (int j= e_shnum; --j>=0; ++shdr) {
|
||||||
if (Elf64_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) {
|
unsigned const sh_type = get_te64(&shdr->sh_type);
|
||||||
xct_va = umin64(xct_va, get_te64(&shdr->sh_addr));
|
if (Elf64_Shdr::SHF_EXECINSTR & get_te64(&shdr->sh_flags)) {
|
||||||
|
xct_va = umin(xct_va, get_te64(&shdr->sh_addr));
|
||||||
|
}
|
||||||
|
// Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY.
|
||||||
|
if (( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init
|
||||||
|
&& Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type)
|
||||||
|
|| ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init
|
||||||
|
&& Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) ) {
|
||||||
|
user_init_off = get_te64(&shdr->sh_offset);
|
||||||
|
user_init_va = get_te64(&file_image[user_init_off]);
|
||||||
|
}
|
||||||
|
// By default /usr/bin/ld leaves 4 extra DT_NULL to support pre-linking.
|
||||||
|
// Take one as a last resort.
|
||||||
|
if ((Elf64_Dyn::DT_INIT==upx_dt_init || !upx_dt_init)
|
||||||
|
&& Elf64_Shdr::SHT_DYNAMIC == sh_type) {
|
||||||
|
unsigned const n = get_te64(&shdr->sh_size) / sizeof(Elf64_Dyn);
|
||||||
|
Elf64_Dyn *dynp = (Elf64_Dyn *)&file_image[shdr->sh_offset];
|
||||||
|
for (; Elf64_Dyn::DT_NULL != dynp->d_tag; ++dynp) {
|
||||||
|
if (upx_dt_init == get_te64(&dynp->d_tag)) {
|
||||||
|
break; // re-found DT_INIT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((1+ dynp) < (n+ dynseg)) { // not the terminator, so take it
|
||||||
|
user_init_va = get_te64(&dynp->d_val); // 0 if (0==upx_dt_init)
|
||||||
|
set_te64(&dynp->d_tag, upx_dt_init = Elf64_Dyn::DT_INIT);
|
||||||
|
user_init_off = (char const *)&dynp->d_val - (char const *)&file_image[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2158,7 +2164,6 @@ proceed: ;
|
|||||||
if (!super::canPack())
|
if (!super::canPack())
|
||||||
return false;
|
return false;
|
||||||
assert(exetype == 1);
|
assert(exetype == 1);
|
||||||
|
|
||||||
exetype = 0;
|
exetype = 0;
|
||||||
|
|
||||||
// set options
|
// set options
|
||||||
@ -4050,9 +4055,6 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
|
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
|
||||||
upx_uint64_t const tag = get_te64(&dyn->d_tag);
|
upx_uint64_t const tag = get_te64(&dyn->d_tag);
|
||||||
upx_uint64_t val = get_te64(&dyn->d_val);
|
upx_uint64_t val = get_te64(&dyn->d_val);
|
||||||
if (upx_dt_init == tag) {
|
|
||||||
set_te64(&dyn->d_val, old_dtinit);
|
|
||||||
}
|
|
||||||
if (is_asl) switch (tag) {
|
if (is_asl) switch (tag) {
|
||||||
case Elf64_Dyn::DT_RELASZ: { dt_relasz = val; } break;
|
case Elf64_Dyn::DT_RELASZ: { dt_relasz = val; } break;
|
||||||
case Elf64_Dyn::DT_RELA: { dt_rela = val; } break;
|
case Elf64_Dyn::DT_RELA: { dt_rela = val; } break;
|
||||||
@ -4067,6 +4069,19 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
set_te64(&dyn->d_val, val - asl_delta);
|
set_te64(&dyn->d_val, val - asl_delta);
|
||||||
}; break;
|
}; break;
|
||||||
} // end switch()
|
} // end switch()
|
||||||
|
if (upx_dt_init == tag) {
|
||||||
|
if (Elf64_Dyn::DT_INIT == tag) {
|
||||||
|
set_te64(&dyn->d_val, old_dtinit);
|
||||||
|
if (!old_dtinit) { // compressor took the slot
|
||||||
|
dyn->d_tag = Elf64_Dyn::DT_NULL;
|
||||||
|
dyn->d_val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // DT_INIT_ARRAY, DT_PREINIT_ARRAY
|
||||||
|
set_te64(&ibuf[val - load_va], old_dtinit
|
||||||
|
+ (is_asl ? asl_delta : 0)); // counter-act unRel64
|
||||||
|
}
|
||||||
|
}
|
||||||
// Modified DT_*.d_val are re-written later from ibuf[]
|
// Modified DT_*.d_val are re-written later from ibuf[]
|
||||||
}
|
}
|
||||||
if (is_asl) {
|
if (is_asl) {
|
||||||
@ -4792,13 +4807,6 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
|||||||
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
|
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
|
||||||
unsigned const tag = get_te32(&dyn->d_tag);
|
unsigned const tag = get_te32(&dyn->d_tag);
|
||||||
unsigned val = get_te32(&dyn->d_val);
|
unsigned val = get_te32(&dyn->d_val);
|
||||||
if (Elf32_Dyn::DT_INIT == tag) {
|
|
||||||
set_te32(&dyn->d_val, old_dtinit);
|
|
||||||
if (!old_dtinit) { // compressor took the slot
|
|
||||||
dyn->d_tag = Elf32_Dyn::DT_NULL;
|
|
||||||
dyn->d_val = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_asl) switch (tag) {
|
if (is_asl) switch (tag) {
|
||||||
case Elf32_Dyn::DT_RELSZ: { dt_relsz = val; } break;
|
case Elf32_Dyn::DT_RELSZ: { dt_relsz = val; } break;
|
||||||
case Elf32_Dyn::DT_REL: { dt_rel = val; } break;
|
case Elf32_Dyn::DT_REL: { dt_rel = val; } break;
|
||||||
@ -4810,9 +4818,22 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
|||||||
case Elf32_Dyn::DT_INIT_ARRAY:
|
case Elf32_Dyn::DT_INIT_ARRAY:
|
||||||
case Elf32_Dyn::DT_FINI_ARRAY:
|
case Elf32_Dyn::DT_FINI_ARRAY:
|
||||||
case Elf32_Dyn::DT_FINI: {
|
case Elf32_Dyn::DT_FINI: {
|
||||||
set_te32(&dyn->d_val, val - asl_delta);
|
set_te32(&dyn->d_val, val -= asl_delta);
|
||||||
}; break;
|
}; break;
|
||||||
} // end switch()
|
} // end switch()
|
||||||
|
if (upx_dt_init == tag) {
|
||||||
|
if (Elf32_Dyn::DT_INIT == tag) {
|
||||||
|
set_te32(&dyn->d_val, old_dtinit);
|
||||||
|
if (!old_dtinit) { // compressor took the slot
|
||||||
|
dyn->d_tag = Elf32_Dyn::DT_NULL;
|
||||||
|
dyn->d_val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // DT_INIT_ARRAY, DT_PREINIT_ARRAY
|
||||||
|
set_te32(&ibuf[val - load_va], old_dtinit
|
||||||
|
+ (is_asl ? asl_delta : 0)); // counter-act unRel32
|
||||||
|
}
|
||||||
|
}
|
||||||
// Modified DT_*.d_val are re-written later from ibuf[]
|
// Modified DT_*.d_val are re-written later from ibuf[]
|
||||||
}
|
}
|
||||||
if (is_asl) {
|
if (is_asl) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user