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

--android-shlib: Relocate ABS _edata etc.

https://github.com/upx/upx/issues/220
	modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
This commit is contained in:
John Reiser 2018-09-16 15:10:40 -07:00
parent 9f294e6ce5
commit 0051dfc84f
2 changed files with 76 additions and 16 deletions

View File

@ -2651,6 +2651,42 @@ PackLinuxElf64::generateElfHdr(
#include "p_elf_enum.h"
#undef WANT_REL_ENUM
// Android shlib has ABS symbols that actually are relative.
static char const abs_symbol_names[][14] = {
"__bss_end__"
, "_bss_end__"
, "__bss_start"
, "__bss_start__"
, "_edata"
, "_end"
, "__end__"
, ""
};
int
PackLinuxElf32::adjABS(Elf32_Sym *sym, unsigned delta)
{
for (int j = 0; abs_symbol_names[j][0]; ++j) {
if (!strcmp(abs_symbol_names[j], &dynstr[sym->st_name])) {
sym->st_value += delta;
return 1;
}
}
return 0;
}
int
PackLinuxElf64::adjABS(Elf64_Sym *sym, unsigned delta)
{
for (int j = 0; abs_symbol_names[j][0]; ++j) {
if (!strcmp(abs_symbol_names[j], &dynstr[sym->st_name])) {
sym->st_value += delta;
return 1;
}
}
return 0;
}
void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
{
fi->seek(0, SEEK_SET);
@ -2741,6 +2777,9 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
&& xct_off <= symval) {
set_te32(&sym->st_value, asl_delta + symval);
}
if (Elf32_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, asl_delta);
}
}
// Relocate Phdr virtual addresses, but not physical offsets and sizes
@ -3135,6 +3174,9 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
&& xct_off <= symval) {
set_te64(&sym->st_value, asl_delta + symval);
}
if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, asl_delta);
}
}
// Relocate Phdr virtual addresses, but not physical offsets and sizes
@ -3989,7 +4031,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
// Packed ET_EXE has no PT_DYNAMIC.
// Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
bool const is_shlib = !!elf_find_ptype(Elf64_Phdr::PT_DYNAMIC, phdri, c_phnum);
Elf64_Phdr const *const dynhdr = elf_find_ptype(Elf64_Phdr::PT_DYNAMIC, phdri, c_phnum);
bool const is_shlib = !!dynhdr;
if (is_shlib) {
// Unpack and output the Ehdr and Phdrs for real.
// This depends on position within input file fi.
@ -3997,9 +4040,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
c_adler, u_adler, false, szb_info);
// The first PT_LOAD. Part is not compressed (for benefit of rtld.)
// Read enough to position the input for next unpackExtent.
fi->seek(0, SEEK_SET);
fi->readx(ibuf, overlay_offset + sizeof(hbuf) + szb_info + ph.c_len);
fi->readx(ibuf, get_te64(&dynhdr->p_offset) + get_te64(&dynhdr->p_filesz));
overlay_offset -= sizeof(linfo);
xct_off = overlay_offset;
e_shoff = get_te64(&ehdri.e_shoff);
@ -4011,6 +4053,9 @@ void PackLinuxElf64::unpack(OutputFile *fo)
xct_off = e_shoff;
}
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
dynseg = (Elf64_Dyn const *)ibuf.subref(
"bad DYNAMIC", get_te64(&dynhdr->p_offset), get_te64(&dynhdr->p_filesz));
dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB);
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset);
upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size);
@ -4025,6 +4070,9 @@ void PackLinuxElf64::unpack(OutputFile *fo)
&& xct_off <= symval) {
set_te64(&sym->st_value, symval - asl_delta);
}
if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, -asl_delta);
}
}
}
if (fo) {
@ -4044,6 +4092,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
total_in = xct_off;
total_out = xct_off;
ph.u_len = 0;
// Position the input for next unpackExtent.
fi->seek(sizeof(linfo) + overlay_offset + sizeof(hbuf) + szb_info + ph.c_len, SEEK_SET);
// Decompress and unfilter the tail of first PT_LOAD.
phdr = (Elf64_Phdr *) (void *) (1+ ehdr);
@ -4150,13 +4200,13 @@ void PackLinuxElf64::unpack(OutputFile *fo)
total_in += old_data_len;
total_out += old_data_len;
Elf64_Phdr *dynhdr = (Elf64_Phdr *)&u[sizeof(*ehdr)];
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr)
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) {
Elf64_Phdr const *udynhdr = (Elf64_Phdr *)&u[sizeof(*ehdr)];
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++udynhdr)
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&udynhdr->p_type)) {
upx_uint64_t dt_pltrelsz(0), dt_jmprel(0);
upx_uint64_t dt_relasz(0), dt_rela(0);
upx_uint64_t const dyn_len = get_te64(&dynhdr->p_filesz);
upx_uint64_t const dyn_off = get_te64(&dynhdr->p_offset);
upx_uint64_t const dyn_len = get_te64(&udynhdr->p_filesz);
upx_uint64_t const dyn_off = get_te64(&udynhdr->p_offset);
if (dyn_off < load_off) {
continue; // Oops. Not really is_shlib ? [built by 'rust' ?]
}
@ -4757,7 +4807,8 @@ void PackLinuxElf32::unpack(OutputFile *fo)
// Packed ET_EXE has no PT_DYNAMIC.
// Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
bool const is_shlib = !!elf_find_ptype(Elf32_Phdr::PT_DYNAMIC, phdri, c_phnum);
Elf32_Phdr const *const dynhdr = elf_find_ptype(Elf32_Phdr::PT_DYNAMIC, phdri, c_phnum);
bool const is_shlib = !!dynhdr;
if (is_shlib) {
// Unpack and output the Ehdr and Phdrs for real.
// This depends on position within input file fi.
@ -4765,9 +4816,8 @@ void PackLinuxElf32::unpack(OutputFile *fo)
c_adler, u_adler, false, szb_info);
// The first PT_LOAD. Part is not compressed (for benefit of rtld.)
// Read enough to position the input for next unpackExtent.
fi->seek(0, SEEK_SET);
fi->readx(ibuf, overlay_offset + sizeof(hbuf) + szb_info + ph.c_len);
fi->readx(ibuf, get_te32(&dynhdr->p_offset) + get_te32(&dynhdr->p_filesz));
overlay_offset -= sizeof(linfo);
xct_off = overlay_offset;
e_shoff = get_te32(&ehdri.e_shoff);
@ -4779,7 +4829,10 @@ void PackLinuxElf32::unpack(OutputFile *fo)
xct_off = e_shoff;
}
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
dynseg = (Elf32_Dyn const *)ibuf.subref(
"bad DYNAMIC", get_te32(&dynhdr->p_offset), get_te32(&dynhdr->p_filesz));
dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB);
sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM);
unsigned const off_dynsym = get_te32(&sec_dynsym->sh_offset);
unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size);
Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref(
@ -4793,6 +4846,9 @@ void PackLinuxElf32::unpack(OutputFile *fo)
&& xct_off <= symval) {
set_te32(&sym->st_value, symval - asl_delta);
}
if (Elf32_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, -asl_delta);
}
}
}
if (fo) {
@ -4812,6 +4868,8 @@ void PackLinuxElf32::unpack(OutputFile *fo)
total_in = xct_off;
total_out = xct_off;
ph.u_len = 0;
// Position the input for next unpackExtent.
fi->seek(sizeof(linfo) + overlay_offset + sizeof(hbuf) + szb_info + ph.c_len, SEEK_SET);
// Decompress and unfilter the tail of first PT_LOAD.
phdr = (Elf32_Phdr *) (void *) (1+ ehdr);
@ -4918,13 +4976,13 @@ void PackLinuxElf32::unpack(OutputFile *fo)
total_in += old_data_len;
total_out += old_data_len;
Elf32_Phdr *dynhdr = (Elf32_Phdr *)&u[sizeof(*ehdr)];
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr)
Elf32_Phdr const *udynhdr = (Elf32_Phdr *)&u[sizeof(*ehdr)];
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++udynhdr)
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) {
unsigned dt_pltrelsz(0), dt_jmprel(0);
unsigned dt_relsz(0), dt_rel(0);
unsigned const dyn_len = get_te32(&dynhdr->p_filesz);
unsigned const dyn_off = get_te32(&dynhdr->p_offset);
unsigned const dyn_len = get_te32(&udynhdr->p_filesz);
unsigned const dyn_off = get_te32(&udynhdr->p_offset);
if (dyn_off < load_off) {
continue; // Oops. Not really is_shlib ? [built by 'rust' ?]
}

View File

@ -161,6 +161,7 @@ protected:
void const *elf_find_dynamic(unsigned) const;
Elf32_Dyn const *elf_has_dynamic(unsigned) const;
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
virtual int adjABS(Elf32_Sym *sym, unsigned delta);
protected:
Elf32_Ehdr ehdri; // from input file
@ -292,6 +293,7 @@ protected:
void const *elf_find_dynamic(unsigned) const;
Elf64_Dyn const *elf_has_dynamic(unsigned) const;
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
virtual int adjABS(Elf64_Sym *sym, unsigned delta);
protected:
Elf64_Ehdr ehdri; // from input file