You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
fix: remote strlen fail in dlopen path; add: GNU ifunc handling to elf_util.c
This commit fixes the remote call to "strlen" fail because ReZygisk ELF utils would not handle GNU indirect functions, making it call the in-between function instead of the actual function.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -159,14 +160,14 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (base) {
|
if (base) {
|
||||||
/* LOGI: Due to the use in zygisk-ptracer, we need to allow pre-
|
/* INFO: Due to the use in zygisk-ptracer, we need to allow pre-
|
||||||
fetched bases to be passed, as the linker (Android 7.1
|
fetched bases to be passed, as the linker (Android 7.1
|
||||||
and below) is not loaded from dlopen, which makes it not
|
and below) is not loaded from dlopen, which makes it not
|
||||||
be visible with dl_iterate_phdr.
|
be visible with dl_iterate_phdr.
|
||||||
*/
|
*/
|
||||||
img->base = base;
|
img->base = base;
|
||||||
|
|
||||||
LOGI("Using provided base address 0x%p for %s", base, elf);
|
LOGD("Using provided base address 0x%p for %s", base, elf);
|
||||||
} else {
|
} else {
|
||||||
if (!_find_module_base(img)) {
|
if (!_find_module_base(img)) {
|
||||||
LOGE("Failed to find module base for %s using dl_iterate_phdr", elf);
|
LOGE("Failed to find module base for %s using dl_iterate_phdr", elf);
|
||||||
@@ -387,7 +388,7 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
|
|||||||
img->symstr_offset_for_symtab = 0;
|
img->symstr_offset_for_symtab = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGI("No .symtab section found or section headers missing");
|
LOGD("No .symtab section found or section headers missing");
|
||||||
|
|
||||||
img->symtab_start = NULL;
|
img->symtab_start = NULL;
|
||||||
img->symtab_count = 0;
|
img->symtab_count = 0;
|
||||||
@@ -403,43 +404,22 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
|
|||||||
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
||||||
bias_calculated = true;
|
bias_calculated = true;
|
||||||
|
|
||||||
LOGI("Calculated bias %ld from PT_LOAD segment %d (vaddr %lx)", (long)img->bias, i, (unsigned long)phdr[i].p_vaddr);
|
LOGD("Calculated bias %ld from PT_LOAD segment %d (vaddr %lx)", (long)img->bias, i, (unsigned long)phdr[i].p_vaddr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bias_calculated) {
|
if (!bias_calculated) for (int i = 0; i < img->header->e_phnum; ++i) {
|
||||||
for (int i = 0; i < img->header->e_phnum; ++i) {
|
if (phdr[i].p_type != PT_LOAD) continue;
|
||||||
if (phdr[i].p_type == PT_LOAD) {
|
|
||||||
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
|
||||||
bias_calculated = true;
|
|
||||||
|
|
||||||
LOGI("Calculated bias %ld from first PT_LOAD segment %d (vaddr %lx, offset %lx)",
|
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
||||||
(long)img->bias, i, (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_offset);
|
bias_calculated = true;
|
||||||
|
|
||||||
break;
|
LOGD("Calculated bias %ld from first PT_LOAD segment %d (vaddr %lx, offset %lx)",
|
||||||
}
|
(long)img->bias, i, (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_offset);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bias_calculated && shdr_base) {
|
break;
|
||||||
LOGW("Could not calculate bias from program headers, falling back to section method.");
|
|
||||||
uintptr_t shoff_for_bias = (uintptr_t)shdr_base;
|
|
||||||
for (int i = 0; i < img->header->e_shnum; i++, shoff_for_bias += img->header->e_shentsize) {
|
|
||||||
ElfW(Shdr) *section_h = (ElfW(Shdr *))shoff_for_bias;
|
|
||||||
|
|
||||||
if ((section_h->sh_flags & SHF_ALLOC) && section_h->sh_addr != 0) {
|
|
||||||
img->bias = (off_t)section_h->sh_addr - (off_t)section_h->sh_offset;
|
|
||||||
bias_calculated = true;
|
|
||||||
|
|
||||||
char *sname = section_str ? (section_h->sh_name + section_str) : "<?>";
|
|
||||||
LOGI("Calculated bias %ld from first allocated section %s (addr %lx, offset %lx)",
|
|
||||||
(long)img->bias, sname, (unsigned long)section_h->sh_addr, (unsigned long)section_h->sh_offset);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,7 +503,7 @@ bool _load_symtabs(ElfImg *img) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash, unsigned char *sym_type) {
|
||||||
if (img->gnu_nbucket_ == 0 || img->gnu_bloom_size_ == 0 || !img->gnu_bloom_filter_ || !img->gnu_bucket_ || !img->gnu_chain_ || !img->dynsym_start || !img->strtab_start)
|
if (img->gnu_nbucket_ == 0 || img->gnu_bloom_size_ == 0 || !img->gnu_bloom_filter_ || !img->gnu_bucket_ || !img->gnu_chain_ || !img->dynsym_start || !img->strtab_start)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -545,7 +525,7 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
|||||||
|
|
||||||
uint32_t sym_index = img->gnu_bucket_[hash % img->gnu_nbucket_];
|
uint32_t sym_index = img->gnu_bucket_[hash % img->gnu_nbucket_];
|
||||||
if (sym_index < img->gnu_symndx_) {
|
if (sym_index < img->gnu_symndx_) {
|
||||||
LOGI("Symbol %s hash %u maps to bucket %u index %u (below gnu_symndx %u), not exported?", name, hash, hash % img->gnu_nbucket_, sym_index, img->gnu_symndx_);
|
LOGW("Symbol %s hash %u maps to bucket %u index %u (below gnu_symndx %u), not exported?", name, hash, hash % img->gnu_nbucket_, sym_index, img->gnu_symndx_);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -568,8 +548,12 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
|
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF) {
|
||||||
|
unsigned int type = ELF_ST_TYPE(sym->st_info);
|
||||||
|
if (sym_type) *sym_type = type;
|
||||||
|
|
||||||
return sym->st_value;
|
return sym->st_value;
|
||||||
|
}
|
||||||
|
|
||||||
while ((chain_val & 1) == 0) {
|
while ((chain_val & 1) == 0) {
|
||||||
sym_index++;
|
sym_index++;
|
||||||
@@ -589,14 +573,18 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
|
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF) {
|
||||||
|
unsigned int type = ELF_ST_TYPE(sym->st_info);
|
||||||
|
if (sym_type) *sym_type = type;
|
||||||
|
|
||||||
return sym->st_value;
|
return sym->st_value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash) {
|
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash, unsigned char *sym_type) {
|
||||||
if (img->nbucket_ == 0 || !img->bucket_ || !img->chain_ || !img->dynsym_start || !img->strtab_start)
|
if (img->nbucket_ == 0 || !img->bucket_ || !img->chain_ || !img->dynsym_start || !img->strtab_start)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -605,14 +593,18 @@ ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t h
|
|||||||
for (size_t n = img->bucket_[hash % img->nbucket_]; n != STN_UNDEF; n = img->chain_[n]) {
|
for (size_t n = img->bucket_[hash % img->nbucket_]; n != STN_UNDEF; n = img->chain_[n]) {
|
||||||
ElfW(Sym) *sym = img->dynsym_start + n;
|
ElfW(Sym) *sym = img->dynsym_start + n;
|
||||||
|
|
||||||
if (strcmp(name, strings + sym->st_name) == 0 && sym->st_shndx != SHN_UNDEF)
|
if (strcmp(name, strings + sym->st_name) == 0 && sym->st_shndx != SHN_UNDEF) {
|
||||||
|
unsigned int type = ELF_ST_TYPE(sym->st_info);
|
||||||
|
if (sym_type) *sym_type = type;
|
||||||
|
|
||||||
return sym->st_value;
|
return sym->st_value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
|
ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name, unsigned char *sym_type) {
|
||||||
if (!_load_symtabs(img)) {
|
if (!_load_symtabs(img)) {
|
||||||
LOGE("Failed to load symtabs for linear lookup of %s", name);
|
LOGE("Failed to load symtabs for linear lookup of %s", name);
|
||||||
|
|
||||||
@@ -623,7 +615,7 @@ ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
|
|||||||
if (valid_symtabs_amount == 0) {
|
if (valid_symtabs_amount == 0) {
|
||||||
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
||||||
@@ -633,13 +625,16 @@ ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
|
|||||||
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
unsigned int type = ELF_ST_TYPE(img->symtabs_[i].sym->st_info);
|
||||||
|
if (sym_type) *sym_type = type;
|
||||||
|
|
||||||
return img->symtabs_[i].sym->st_value;
|
return img->symtabs_[i].sym->st_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
|
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix, unsigned char *sym_type) {
|
||||||
if (!_load_symtabs(img)) {
|
if (!_load_symtabs(img)) {
|
||||||
LOGE("Failed to load symtabs for linear lookup by prefix of %s", prefix);
|
LOGE("Failed to load symtabs for linear lookup by prefix of %s", prefix);
|
||||||
|
|
||||||
@@ -650,7 +645,7 @@ ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
|
|||||||
if (valid_symtabs_amount == 0) {
|
if (valid_symtabs_amount == 0) {
|
||||||
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t prefix_len = strlen(prefix);
|
size_t prefix_len = strlen(prefix);
|
||||||
@@ -666,45 +661,161 @@ ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
|
|||||||
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
unsigned int type = ELF_ST_TYPE(img->symtabs_[i].sym->st_info);
|
||||||
|
if (sym_type) *sym_type = type;
|
||||||
|
|
||||||
return img->symtabs_[i].sym->st_value;
|
return img->symtabs_[i].sym->st_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name) {
|
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name, unsigned char *sym_type) {
|
||||||
ElfW(Addr) offset = 0;
|
ElfW(Addr) offset = 0;
|
||||||
|
|
||||||
offset = GnuLookup(img, name, GnuHash(name));
|
offset = GnuLookup(img, name, GnuHash(name), sym_type);
|
||||||
if (offset != 0) return offset;
|
if (offset != 0) return offset;
|
||||||
|
|
||||||
offset = ElfLookup(img, name, ElfHash(name));
|
offset = ElfLookup(img, name, ElfHash(name), sym_type);
|
||||||
if (offset != 0) return offset;
|
if (offset != 0) return offset;
|
||||||
|
|
||||||
offset = LinearLookup(img, name);
|
offset = LinearLookup(img, name, sym_type);
|
||||||
if (offset != 0) return offset;
|
if (offset != 0) return offset;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
/* INFO: Struct containing information about hardware capabilities used in resolver. This
|
||||||
|
struct information is pulled directly from the AOSP code.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/ifunc.h#53
|
||||||
|
*/
|
||||||
|
struct __ifunc_arg_t {
|
||||||
|
unsigned long _size;
|
||||||
|
unsigned long _hwcap;
|
||||||
|
unsigned long _hwcap2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* INFO: This is a constant used in the AOSP code to indicate that the struct __ifunc_arg_t
|
||||||
|
contains hardware capabilities.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/ifunc.h#74
|
||||||
|
*/
|
||||||
|
#define _IFUNC_ARG_HWCAP (1ULL << 62)
|
||||||
|
#elif defined(__riscv)
|
||||||
|
/* INFO: Struct used in Linux RISC-V architecture to probe hardware capabilities.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/kernel/uapi/asm-riscv/asm/hwprobe.h#10
|
||||||
|
*/
|
||||||
|
struct riscv_hwprobe {
|
||||||
|
int64_t key;
|
||||||
|
uint64_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* INFO: This function is used in the AOSP code to probe hardware capabilities on RISC-V architecture
|
||||||
|
by calling the syscall __NR_riscv_hwprobe and passing the parameters that will filled with
|
||||||
|
the device hardware capabilities.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/bionic/vdso.cpp#86
|
||||||
|
*/
|
||||||
|
int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpu_count, unsigned long *cpus, unsigned flags) {
|
||||||
|
register long a0 __asm__("a0") = (long)pairs;
|
||||||
|
register long a1 __asm__("a1") = pair_count;
|
||||||
|
register long a2 __asm__("a2") = cpu_count;
|
||||||
|
register long a3 __asm__("a3") = (long)cpus;
|
||||||
|
register long a4 __asm__("a4") = flags;
|
||||||
|
register long a7 __asm__("a7") = __NR_riscv_hwprobe;
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
"ecall"
|
||||||
|
: "=r"(a0)
|
||||||
|
: "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a7)
|
||||||
|
);
|
||||||
|
|
||||||
|
return -a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFO: This is a function pointer type that points how the signature of the __riscv_hwprobe
|
||||||
|
function is.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/hwprobe.h#62
|
||||||
|
*/
|
||||||
|
typedef int (*__riscv_hwprobe_t)(struct riscv_hwprobe *__pairs, size_t __pair_count, size_t __cpu_count, unsigned long *__cpus, unsigned __flags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* INFO: GNU ifuncs (indirect functions) are functions that does not execute the code by itself,
|
||||||
|
but instead lead to other functions that may very according to hardware capabilities,
|
||||||
|
or other reasons, depending of the architecture.
|
||||||
|
|
||||||
|
This function is based on AOSP's (Android Open Source Project) code, and resolves the
|
||||||
|
indirect symbol, leading to the correct, most appropriate for the hardware, symbol.
|
||||||
|
|
||||||
|
SOURCES:
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/linker/linker.cpp#2594
|
||||||
|
- https://android.googlesource.com/platform/bionic/+/tags/android-16.0.0_r1/libc/bionic/bionic_call_ifunc_resolver.cpp#41
|
||||||
|
*/
|
||||||
|
static ElfW(Addr) handle_indirect_symbol(ElfImg *img, ElfW(Off) offset) {
|
||||||
|
ElfW(Addr) resolver_addr = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, struct __ifunc_arg_t *);
|
||||||
|
|
||||||
|
struct __ifunc_arg_t args = {
|
||||||
|
._size = sizeof(struct __ifunc_arg_t),
|
||||||
|
._hwcap = getauxval(AT_HWCAP),
|
||||||
|
._hwcap2 = getauxval(AT_HWCAP2)
|
||||||
|
};
|
||||||
|
|
||||||
|
return ((ifunc_resolver_t)resolver_addr)(args._hwcap | _IFUNC_ARG_HWCAP, &args);
|
||||||
|
#elif defined(__arm__)
|
||||||
|
typedef ElfW(Addr) (*ifunc_resolver_t)(unsigned long);
|
||||||
|
|
||||||
|
return ((ifunc_resolver_t)resolver_addr)(getauxval(AT_HWCAP));
|
||||||
|
#elif defined(__riscv)
|
||||||
|
typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, __riscv_hwprobe_t, void *);
|
||||||
|
|
||||||
|
return ((ifunc_resolver_t)resolver_addr)(getauxval(AT_HWCAP), __riscv_hwprobe, NULL);
|
||||||
|
#else
|
||||||
|
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
||||||
|
|
||||||
|
return ((ifunc_resolver_t)resolver_addr)();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name) {
|
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name) {
|
||||||
ElfW(Addr) offset = getSymbOffset(img, name);
|
unsigned char sym_type = 0;
|
||||||
|
ElfW(Addr) offset = getSymbOffset(img, name, &sym_type);
|
||||||
|
|
||||||
if (offset == 0 || !img->base) return 0;
|
if (offset == 0 || !img->base) return 0;
|
||||||
|
|
||||||
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
if (sym_type == STT_GNU_IFUNC) {
|
||||||
|
LOGD("Resolving STT_GNU_IFUNC symbol %s", name);
|
||||||
|
|
||||||
return address;
|
return handle_indirect_symbol(img, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Addr) getSymbAddressByPrefix(ElfImg *img, const char *prefix) {
|
ElfW(Addr) getSymbAddressByPrefix(ElfImg *img, const char *prefix) {
|
||||||
ElfW(Addr) offset = LinearLookupByPrefix(img, prefix);
|
unsigned char sym_type = 0;
|
||||||
|
ElfW(Addr) offset = LinearLookupByPrefix(img, prefix, &sym_type);
|
||||||
|
|
||||||
if (offset == 0 || !img->base) return 0;
|
if (offset == 0 || !img->base) return 0;
|
||||||
|
|
||||||
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
if (sym_type == STT_GNU_IFUNC) {
|
||||||
|
LOGD("Resolving STT_GNU_IFUNC symbol by prefix %s", prefix);
|
||||||
|
|
||||||
return address;
|
return handle_indirect_symbol(img, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getSymbValueByPrefix(ElfImg *img, const char *prefix) {
|
void *getSymbValueByPrefix(ElfImg *img, const char *prefix) {
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
#ifndef ELF_UTIL_H
|
#ifndef ELF_UTIL_H
|
||||||
#define ELF_UTIL_H
|
#define ELF_UTIL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#include <linux/elf.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <pthread.h> // Added for threading primitives
|
||||||
|
|
||||||
#define SHT_GNU_HASH 0x6ffffff6
|
#define SHT_GNU_HASH 0x6ffffff6
|
||||||
|
|
||||||
|
// Function pointer types for constructors and destructors
|
||||||
|
typedef void (*linker_simple_func_t)(void);
|
||||||
|
typedef void (*linker_ctor_function_t)(int, char**, char**);
|
||||||
|
typedef void (*linker_dtor_function_t)(void);
|
||||||
|
|
||||||
|
|
||||||
struct symtabs {
|
struct symtabs {
|
||||||
char *name;
|
char *name;
|
||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
@@ -54,17 +61,7 @@ void ElfImg_destroy(ElfImg *img);
|
|||||||
|
|
||||||
ElfImg *ElfImg_create(const char *elf, void *base);
|
ElfImg *ElfImg_create(const char *elf, void *base);
|
||||||
|
|
||||||
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash);
|
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name, unsigned char *sym_type);
|
||||||
|
|
||||||
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash);
|
|
||||||
|
|
||||||
ElfW(Addr) LinearLookup(ElfImg *restrict img, const char *restrict name);
|
|
||||||
|
|
||||||
ElfW(Addr) LinearLookupByPrefix(ElfImg *restrict img, const char *name);
|
|
||||||
|
|
||||||
int dl_cb(struct dl_phdr_info *info, size_t size, void *data);
|
|
||||||
|
|
||||||
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name);
|
|
||||||
|
|
||||||
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name);
|
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name);
|
||||||
|
|
||||||
|
|||||||
@@ -161,13 +161,15 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
|
|
||||||
const char *libdl_path = NULL;
|
const char *libdl_path = NULL;
|
||||||
const char *libc_path = NULL;
|
const char *libc_path = NULL;
|
||||||
for (size_t i = 0; i < local_map->size; i++) {
|
for (size_t i = 0; i < map->size; i++) {
|
||||||
if (local_map->maps[i].path == NULL) continue;
|
if (map->maps[i].path == NULL) continue;
|
||||||
|
|
||||||
const char *filename = position_after(local_map->maps[i].path, '/');
|
const char *filename = position_after(map->maps[i].path, '/');
|
||||||
|
|
||||||
if (strcmp(filename, "libdl.so") == 0) {
|
if (!libdl_path && strcmp(filename, "libdl.so") == 0) {
|
||||||
libdl_path = local_map->maps[i].path;
|
libdl_path = map->maps[i].path;
|
||||||
|
|
||||||
|
LOGD("found libdl.so at %s", libdl_path);
|
||||||
|
|
||||||
/* INFO: If we had found libc.so too, no need to continue searching */
|
/* INFO: If we had found libc.so too, no need to continue searching */
|
||||||
if (libc_path) break;
|
if (libc_path) break;
|
||||||
@@ -175,8 +177,10 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(filename, "libc.so") == 0) {
|
if (!libc_path && strcmp(filename, "libc.so") == 0) {
|
||||||
libc_path = local_map->maps[i].path;
|
libc_path = map->maps[i].path;
|
||||||
|
|
||||||
|
LOGD("found libc.so at %s", libc_path);
|
||||||
|
|
||||||
/* INFO: If we had found libdl.so too, no need to continue searching */
|
/* INFO: If we had found libdl.so too, no need to continue searching */
|
||||||
if (libdl_path) break;
|
if (libdl_path) break;
|
||||||
|
|||||||
Reference in New Issue
Block a user