32-bit ARM Android shlib: DT_INIT_ARRAY without DT_INIT

De-compressor needs to catch up.
	modified:   p_elf_enum.h
	modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
	modified:   stub/src/i386-linux.elf-so_main.c
This commit is contained in:
John Reiser
2023-03-22 10:44:17 -07:00
parent 5b113a5041
commit 06fae05910
4 changed files with 124 additions and 64 deletions
+19 -28
View File
@@ -34,7 +34,7 @@
extern void my_bkpt(void const *arg1, ...);
#define DEBUG 0
#define DEBUG 1
void *mmap(void *, size_t, int, int, int, off_t);
#if defined(__i386__) || defined(__mips__) || defined(__powerpc__) //{
@@ -525,37 +525,26 @@ upx_so_main( // returns &escape_hatch
Extent x0 = {binfo->sz_cpr + sizeof(*binfo), (char *)binfo}; // source
unpackExtent(&x0, &x1); // de-compress Elf headers; x0.buf is updated
// Count PT_LOAD; n_LOAD < 3 is special (old binutils PT_LOAD layout)
unsigned n_phdr;
Elf32_Phdr const *phdr;
n_phdr = ((Elf32_Ehdr *)(void *)va_load)->e_phnum;
phdr = (Elf32_Phdr *)(1+ (Elf32_Ehdr *)(void *)va_load);
unsigned n_LOAD = 0;
for (; n_phdr > 0; --n_phdr, ++phdr) {
n_LOAD += (PT_LOAD == phdr->p_type);
}
// Old-style binutils with only 2 PT_LOAD: (r-x) and (rw-)
// has xct_off in middle of first PT_LOAD.
// New-style binutils has xct-off at beginning of 2nd PT_LOAD.
Elf32_Addr pfx = (n_LOAD <= 2) ? so_infc.off_xct_off : 0;
// Process each read-only PT_LOAD.
// A read+write PT_LOAD might be relocated by rtld before de-compression,
// so it cannot be compressed.
struct b_info al_bi; // for aligned data from binfo
void *hatch = nullptr;
unsigned not_first = 0;
n_phdr = ((Elf32_Ehdr *)(void *)va_load)->e_phnum;
phdr = (Elf32_Phdr *)(1+ (Elf32_Ehdr *)(void *)va_load);
Elf32_Phdr const *phdr = (Elf32_Phdr *)(1+ (Elf32_Ehdr *)(void *)va_load);
unsigned n_phdr = ((Elf32_Ehdr *)(void *)va_load)->e_phnum;
for (; n_phdr > 0; --n_phdr, ++phdr)
if ( phdr->p_type == PT_LOAD
&& !(phdr->p_flags & PF_W)
&& (not_first++ || n_LOAD < 3)
) {
DPRINTF("phdr@%%p .p_vaddr=%%p .p_filesz=%%p .p_memsz=%%p n_LOAD=%%p binfo=%%p\\n",
phdr, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, n_LOAD, x0.buf);
if ( phdr->p_type == PT_LOAD && !(phdr->p_flags & PF_W)) {
DPRINTF("phdr@%%p p_offset=%%p p_vaddr=%%p p_filesz=%%p p_memsz=%%p binfo=%%p\\n",
phdr, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, x0.buf);
if ((phdr->p_filesz + phdr->p_offset) <= so_infc.off_xct_off) {
continue; // below compressed region
}
Elf32_Addr pfx = so_infc.off_xct_off - phdr->p_offset;
if ( so_infc.off_xct_off < phdr->p_offset) {
pfx = 0; // no more partially-compressed PT_LOAD
}
x0.size = sizeof(struct b_info);
xread(&x0, (char *)&al_bi, x0.size); // aligned binfo
x0.buf -= sizeof(al_bi); // back up (the xread() was a peek)
@@ -563,9 +552,11 @@ upx_so_main( // returns &escape_hatch
al_bi.sz_unc, al_bi.sz_cpr, *(unsigned *)(void *)&al_bi.b_method);
// Using .p_memsz implicitly handles .bss via MAP_ANONYMOUS.
// Omit any not-compressed prefix (below xct_off)
x1.buf = phdr->p_vaddr + pfx + va_load;
x1.size = phdr->p_memsz - pfx;
pfx = (phdr->p_vaddr + pfx) & ~PAGE_MASK;
pfx = (phdr->p_vaddr + pfx) & ~PAGE_MASK; // lo fragment on page
x1.buf -= pfx;
x1.size += pfx;
DPRINTF("mmap(%%p %%p) xct_off=%%x pfx=%%x\\n", x1.buf, x1.size, xct_off, pfx);
@@ -575,7 +566,6 @@ upx_so_main( // returns &escape_hatch
x1.size = al_bi.sz_unc;
x0.size = al_bi.sz_cpr + sizeof(struct b_info);
unpackExtent(&x0, &x1); // updates x0 and x1
pfx = 0; // consider xct_off at most once
if (!hatch && phdr->p_flags & PF_X) {
//#define PAGE_MASK ~0xFFFull
@@ -587,8 +577,9 @@ upx_so_main( // returns &escape_hatch
hatch = make_hatch_i386(phdr, (Elf32_Addr)va_load);
#endif //}
}
DPRINTF("mprotect %%p (%%p %%p)\\n", phdr, phdr->p_vaddr + va_load, phdr->p_memsz);
mprotect(phdr->p_vaddr + va_load, phdr->p_memsz, PF_TO_PROT(phdr->p_flags));
DPRINTF("mprotect %%p (%%p %%p %%x)\\n",
phdr, phdr->p_vaddr + va_load, phdr->p_memsz, PF_TO_PROT(phdr->p_flags));
mprotect( phdr->p_vaddr + va_load, phdr->p_memsz, PF_TO_PROT(phdr->p_flags));
}
typedef void (*Dt_init)(int argc, char *argv[], char *envp[]);