mirror of
https://github.com/upx/upx
synced 2025-10-05 19:20:23 +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:
parent
9f294e6ce5
commit
0051dfc84f
|
@ -2651,6 +2651,42 @@ PackLinuxElf64::generateElfHdr(
|
||||||
#include "p_elf_enum.h"
|
#include "p_elf_enum.h"
|
||||||
#undef WANT_REL_ENUM
|
#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*/)
|
void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||||
{
|
{
|
||||||
fi->seek(0, SEEK_SET);
|
fi->seek(0, SEEK_SET);
|
||||||
|
@ -2741,6 +2777,9 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||||
&& xct_off <= symval) {
|
&& xct_off <= symval) {
|
||||||
set_te32(&sym->st_value, asl_delta + 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
|
// Relocate Phdr virtual addresses, but not physical offsets and sizes
|
||||||
|
@ -3135,6 +3174,9 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||||
&& xct_off <= symval) {
|
&& xct_off <= symval) {
|
||||||
set_te64(&sym->st_value, asl_delta + 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
|
// 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_EXE has no PT_DYNAMIC.
|
||||||
// Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
|
// 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) {
|
if (is_shlib) {
|
||||||
// Unpack and output the Ehdr and Phdrs for real.
|
// Unpack and output the Ehdr and Phdrs for real.
|
||||||
// This depends on position within input file fi.
|
// This depends on position within input file fi.
|
||||||
|
@ -3997,9 +4040,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
||||||
c_adler, u_adler, false, szb_info);
|
c_adler, u_adler, false, szb_info);
|
||||||
|
|
||||||
// The first PT_LOAD. Part is not compressed (for benefit of rtld.)
|
// 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->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);
|
overlay_offset -= sizeof(linfo);
|
||||||
xct_off = overlay_offset;
|
xct_off = overlay_offset;
|
||||||
e_shoff = get_te64(&ehdri.e_shoff);
|
e_shoff = get_te64(&ehdri.e_shoff);
|
||||||
|
@ -4011,6 +4053,9 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
||||||
xct_off = e_shoff;
|
xct_off = e_shoff;
|
||||||
}
|
}
|
||||||
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
|
// 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);
|
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 off_dynsym = get_te64(&sec_dynsym->sh_offset);
|
||||||
upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size);
|
upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size);
|
||||||
|
@ -4025,6 +4070,9 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
||||||
&& xct_off <= symval) {
|
&& xct_off <= symval) {
|
||||||
set_te64(&sym->st_value, symval - asl_delta);
|
set_te64(&sym->st_value, symval - asl_delta);
|
||||||
}
|
}
|
||||||
|
if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) {
|
||||||
|
adjABS(sym, -asl_delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fo) {
|
if (fo) {
|
||||||
|
@ -4044,6 +4092,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
||||||
total_in = xct_off;
|
total_in = xct_off;
|
||||||
total_out = xct_off;
|
total_out = xct_off;
|
||||||
ph.u_len = 0;
|
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.
|
// Decompress and unfilter the tail of first PT_LOAD.
|
||||||
phdr = (Elf64_Phdr *) (void *) (1+ ehdr);
|
phdr = (Elf64_Phdr *) (void *) (1+ ehdr);
|
||||||
|
@ -4150,13 +4200,13 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
||||||
total_in += old_data_len;
|
total_in += old_data_len;
|
||||||
total_out += old_data_len;
|
total_out += old_data_len;
|
||||||
|
|
||||||
Elf64_Phdr *dynhdr = (Elf64_Phdr *)&u[sizeof(*ehdr)];
|
Elf64_Phdr const *udynhdr = (Elf64_Phdr *)&u[sizeof(*ehdr)];
|
||||||
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr)
|
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++udynhdr)
|
||||||
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) {
|
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&udynhdr->p_type)) {
|
||||||
upx_uint64_t dt_pltrelsz(0), dt_jmprel(0);
|
upx_uint64_t dt_pltrelsz(0), dt_jmprel(0);
|
||||||
upx_uint64_t dt_relasz(0), dt_rela(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_len = get_te64(&udynhdr->p_filesz);
|
||||||
upx_uint64_t const dyn_off = get_te64(&dynhdr->p_offset);
|
upx_uint64_t const dyn_off = get_te64(&udynhdr->p_offset);
|
||||||
if (dyn_off < load_off) {
|
if (dyn_off < load_off) {
|
||||||
continue; // Oops. Not really is_shlib ? [built by 'rust' ?]
|
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_EXE has no PT_DYNAMIC.
|
||||||
// Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
|
// 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) {
|
if (is_shlib) {
|
||||||
// Unpack and output the Ehdr and Phdrs for real.
|
// Unpack and output the Ehdr and Phdrs for real.
|
||||||
// This depends on position within input file fi.
|
// This depends on position within input file fi.
|
||||||
|
@ -4765,9 +4816,8 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
||||||
c_adler, u_adler, false, szb_info);
|
c_adler, u_adler, false, szb_info);
|
||||||
|
|
||||||
// The first PT_LOAD. Part is not compressed (for benefit of rtld.)
|
// 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->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);
|
overlay_offset -= sizeof(linfo);
|
||||||
xct_off = overlay_offset;
|
xct_off = overlay_offset;
|
||||||
e_shoff = get_te32(&ehdri.e_shoff);
|
e_shoff = get_te32(&ehdri.e_shoff);
|
||||||
|
@ -4779,7 +4829,10 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
||||||
xct_off = e_shoff;
|
xct_off = e_shoff;
|
||||||
}
|
}
|
||||||
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
|
// 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 off_dynsym = get_te32(&sec_dynsym->sh_offset);
|
||||||
unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size);
|
unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size);
|
||||||
Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref(
|
Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref(
|
||||||
|
@ -4793,6 +4846,9 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
||||||
&& xct_off <= symval) {
|
&& xct_off <= symval) {
|
||||||
set_te32(&sym->st_value, symval - asl_delta);
|
set_te32(&sym->st_value, symval - asl_delta);
|
||||||
}
|
}
|
||||||
|
if (Elf32_Sym::SHN_ABS == symsec && xct_off <= symval) {
|
||||||
|
adjABS(sym, -asl_delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fo) {
|
if (fo) {
|
||||||
|
@ -4812,6 +4868,8 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
||||||
total_in = xct_off;
|
total_in = xct_off;
|
||||||
total_out = xct_off;
|
total_out = xct_off;
|
||||||
ph.u_len = 0;
|
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.
|
// Decompress and unfilter the tail of first PT_LOAD.
|
||||||
phdr = (Elf32_Phdr *) (void *) (1+ ehdr);
|
phdr = (Elf32_Phdr *) (void *) (1+ ehdr);
|
||||||
|
@ -4918,13 +4976,13 @@ void PackLinuxElf32::unpack(OutputFile *fo)
|
||||||
total_in += old_data_len;
|
total_in += old_data_len;
|
||||||
total_out += old_data_len;
|
total_out += old_data_len;
|
||||||
|
|
||||||
Elf32_Phdr *dynhdr = (Elf32_Phdr *)&u[sizeof(*ehdr)];
|
Elf32_Phdr const *udynhdr = (Elf32_Phdr *)&u[sizeof(*ehdr)];
|
||||||
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr)
|
for (unsigned j3= 0; j3 < u_phnum; ++j3, ++udynhdr)
|
||||||
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) {
|
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) {
|
||||||
unsigned dt_pltrelsz(0), dt_jmprel(0);
|
unsigned dt_pltrelsz(0), dt_jmprel(0);
|
||||||
unsigned dt_relsz(0), dt_rel(0);
|
unsigned dt_relsz(0), dt_rel(0);
|
||||||
unsigned const dyn_len = get_te32(&dynhdr->p_filesz);
|
unsigned const dyn_len = get_te32(&udynhdr->p_filesz);
|
||||||
unsigned const dyn_off = get_te32(&dynhdr->p_offset);
|
unsigned const dyn_off = get_te32(&udynhdr->p_offset);
|
||||||
if (dyn_off < load_off) {
|
if (dyn_off < load_off) {
|
||||||
continue; // Oops. Not really is_shlib ? [built by 'rust' ?]
|
continue; // Oops. Not really is_shlib ? [built by 'rust' ?]
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,7 @@ protected:
|
||||||
void const *elf_find_dynamic(unsigned) const;
|
void const *elf_find_dynamic(unsigned) const;
|
||||||
Elf32_Dyn const *elf_has_dynamic(unsigned) const;
|
Elf32_Dyn const *elf_has_dynamic(unsigned) const;
|
||||||
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
|
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
|
||||||
|
virtual int adjABS(Elf32_Sym *sym, unsigned delta);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Elf32_Ehdr ehdri; // from input file
|
Elf32_Ehdr ehdri; // from input file
|
||||||
|
@ -292,6 +293,7 @@ protected:
|
||||||
void const *elf_find_dynamic(unsigned) const;
|
void const *elf_find_dynamic(unsigned) const;
|
||||||
Elf64_Dyn const *elf_has_dynamic(unsigned) const;
|
Elf64_Dyn const *elf_has_dynamic(unsigned) const;
|
||||||
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
|
virtual upx_uint64_t elf_unsigned_dynamic(unsigned) const;
|
||||||
|
virtual int adjABS(Elf64_Sym *sym, unsigned delta);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Elf64_Ehdr ehdri; // from input file
|
Elf64_Ehdr ehdri; // from input file
|
||||||
|
|
Loading…
Reference in New Issue
Block a user