better libc detection, use DT_TEXTREL when possible instead of making a segment RWX
This commit is contained in:
parent
00632e9548
commit
c3248c6801
78
manip-exe.h
78
manip-exe.h
|
@ -6,9 +6,9 @@
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
|
|
||||||
#if (sizeof(ElfW(Ehdr)) != sizeof(Elf64_Ehdr))
|
/*#if sizeof(ElfW(Ehdr)) != sizeof(Elf64_Ehdr)
|
||||||
#error "Need 64-bit ELF for now, sorry"
|
#error "Need 64-bit ELF for now, sorry"
|
||||||
#endif
|
#endif*/
|
||||||
|
|
||||||
static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
||||||
if (elf->e_ident[0] != ELFMAG0 || elf->e_ident[1] != ELFMAG1
|
if (elf->e_ident[0] != ELFMAG0 || elf->e_ident[1] != ELFMAG1
|
||||||
|
@ -33,13 +33,23 @@ static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
||||||
|
|
||||||
ElfW(Phdr)* phdr = (ElfW(Phdr)*)(elf->e_phoff + (size_t)elf), *ph_loadexec;
|
ElfW(Phdr)* phdr = (ElfW(Phdr)*)(elf->e_phoff + (size_t)elf), *ph_loadexec;
|
||||||
ElfW(Dyn)* dyn = NULL;
|
ElfW(Dyn)* dyn = NULL;
|
||||||
|
bool textrel = false;
|
||||||
|
enum {
|
||||||
|
libc_unk, libc_g /* glibc */, libc_musl, libc_uc /* uclibc */
|
||||||
|
} libc = libc_unk;
|
||||||
|
// first, try to determine the libc used
|
||||||
for (size_t i = 0; i < elf->e_phnum;
|
for (size_t i = 0; i < elf->e_phnum;
|
||||||
++i, phdr = (ElfW(Phdr)*)((size_t)phdr + elf->e_phentsize)) {
|
++i, phdr = (ElfW(Phdr)*)((size_t)phdr + elf->e_phentsize)) {
|
||||||
if (phdr->p_type == PT_LOAD) {
|
if (phdr->p_type == PT_INTERP) {
|
||||||
// need this at runtime for the relocs to work (yeah, sorry)
|
const char* str = (char*)elf + phdr->p_offset;
|
||||||
if (phdr->p_flags & PF_X) {
|
if (!strcmp(str, "/lib64/ld-linux-x86-64.so.2")) {
|
||||||
ph_loadexec = phdr;
|
libc = libc_g;
|
||||||
phdr->p_flags |= PF_W;
|
printf("\tglibc\n");
|
||||||
|
} else if (!strcmp(str, "/lib/ld-musl-x86_64.so.1")) {
|
||||||
|
libc = libc_musl;
|
||||||
|
printf("\tmusl\n");
|
||||||
|
} else {
|
||||||
|
printf("\tunknown libc: '%s'\n", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +59,55 @@ static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (libc == libc_unk) {
|
||||||
|
ElfW(Dyn)* dd = dyn;
|
||||||
|
const char* ddstr = NULL;
|
||||||
|
for (size_t i = 0; dd->d_tag != DT_NULL; ++i, ++dd) {
|
||||||
|
if (dd->d_tag == DT_STRTAB)
|
||||||
|
ddstr = (const char*)((size_t)elf + dd->d_un.d_ptr);
|
||||||
|
}
|
||||||
|
dd = dyn;
|
||||||
|
for (size_t i = 0; dd->d_tag != DT_NULL; ++i, ++dd) {
|
||||||
|
if (dd->d_tag == DT_NEEDED) {
|
||||||
|
const char* s = ddstr + dd->d_un.d_val;
|
||||||
|
|
||||||
|
if (strstr(s, "libc.so") != s) continue;
|
||||||
|
|
||||||
|
if (!strcmp(s, "libc.so.6")) {
|
||||||
|
libc = libc_g;
|
||||||
|
printf("\tglibc\n");
|
||||||
|
break;
|
||||||
|
} else if (!strcmp(s, "libc.so.0")) {
|
||||||
|
libc = libc_uc;
|
||||||
|
printf("\tuclibc\n");
|
||||||
|
break;
|
||||||
|
} else if (!strcmp(s, "libc.so")) {
|
||||||
|
libc = libc_musl;
|
||||||
|
printf("\tmusl\n");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
printf("\tunknown libc: '%s'\n", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
phdr = (ElfW(Phdr)*)(elf->e_phoff + (size_t)elf);
|
||||||
|
for (size_t i = 0; i < elf->e_phnum;
|
||||||
|
++i, phdr = (ElfW(Phdr)*)((size_t)phdr + elf->e_phentsize)) {
|
||||||
|
if (phdr->p_type == PT_LOAD) {
|
||||||
|
// need this at runtime for the relocs to work (yeah, sorry)
|
||||||
|
if (phdr->p_flags & PF_X) {
|
||||||
|
ph_loadexec = phdr;
|
||||||
|
if (libc == libc_g || libc == libc_uc) {
|
||||||
|
textrel = true;
|
||||||
|
} else {
|
||||||
|
phdr->p_flags |= PF_W;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dyn == NULL) {
|
if (dyn == NULL) {
|
||||||
fprintf(stderr, "No DYNAMIC table! bailing out...\n");
|
fprintf(stderr, "No DYNAMIC table! bailing out...\n");
|
||||||
return true;
|
return true;
|
||||||
|
@ -63,6 +122,7 @@ static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
||||||
ElfW(Addr) relaoff = 0;
|
ElfW(Addr) relaoff = 0;
|
||||||
|
|
||||||
for (size_t i = 0; dyn->d_tag != DT_NULL; ++i, ++dyn) {
|
for (size_t i = 0; dyn->d_tag != DT_NULL; ++i, ++dyn) {
|
||||||
|
if (dyn->d_tag == DT_TEXTREL) textrel = false;
|
||||||
if (dyn->d_tag == DT_RELA) {
|
if (dyn->d_tag == DT_RELA) {
|
||||||
relatab = (ElfW(Rela)*)((size_t)elf + dyn->d_un.d_ptr);
|
relatab = (ElfW(Rela)*)((size_t)elf + dyn->d_un.d_ptr);
|
||||||
relaoff = dyn->d_un.d_ptr;
|
relaoff = dyn->d_un.d_ptr;
|
||||||
|
@ -80,6 +140,10 @@ static bool manip_elf(ElfW(Ehdr)* elf, const char* symname) {
|
||||||
if (dyn->d_tag == DT_SYMENT) syment = dyn->d_un.d_val;
|
if (dyn->d_tag == DT_SYMENT) syment = dyn->d_un.d_val;
|
||||||
if (dyn->d_tag == DT_STRSZ ) strsz = dyn->d_un.d_val;
|
if (dyn->d_tag == DT_STRSZ ) strsz = dyn->d_un.d_val;
|
||||||
}
|
}
|
||||||
|
if (textrel) {
|
||||||
|
dyn->d_tag = DT_TEXTREL; // need this one
|
||||||
|
dyn[1].d_tag = DT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!relasz || !relaent || !relatab) {
|
if (!relasz || !relaent || !relatab) {
|
||||||
fprintf(stderr, "No RELA/RELASZ/RELAENT in DYN!\n");
|
fprintf(stderr, "No RELA/RELASZ/RELAENT in DYN!\n");
|
||||||
|
|
Loading…
Reference in New Issue