Files
Zygisk-MyInjector/module/src/main/cpp/mylinker/utils.cpp
2025-06-26 19:59:33 +08:00

157 lines
4.5 KiB
C++

#include "utils.h"
namespace Utils {
bool safe_add(off64_t* out, off64_t a, size_t b) {
if (a < 0 || __builtin_add_overflow(a, b, out)) {
return false;
}
return true;
}
soinfo* get_soinfo(const char* so_name) {
typedef soinfo* (*FunctionPtr)(ElfW(Addr));
char line[1024];
ElfW(Addr) linker_base = 0;
ElfW(Addr) so_addr = 0;
FILE* fp = fopen("/proc/self/maps", "r");
if (!fp) {
LOGE("Cannot open /proc/self/maps");
return nullptr;
}
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, "linker64") && !linker_base) {
char* addr = strtok(line, "-");
linker_base = strtoull(addr, nullptr, 16);
} else if (strstr(line, so_name) && !so_addr) {
char* addr = strtok(line, "-");
so_addr = strtoull(addr, nullptr, 16);
}
if (linker_base && so_addr) {
break;
}
}
fclose(fp);
if (!linker_base || !so_addr) {
LOGE("Cannot find addresses");
return nullptr;
}
ElfW(Addr) func_offset = get_export_func("/system/bin/linker64", "find_containing_library");
if (!func_offset) {
LOGE("Cannot find find_containing_library");
return nullptr;
}
ElfW(Addr) find_containing_library_addr = linker_base + func_offset;
FunctionPtr find_containing_library = reinterpret_cast<FunctionPtr>(find_containing_library_addr);
return find_containing_library(so_addr);
}
void* getMapData(int fd, off64_t base_offset, size_t elf_offset, size_t size) {
off64_t offset;
if (!safe_add(&offset, base_offset, elf_offset)) {
return nullptr;
}
off64_t page_min = page_start(offset);
off64_t end_offset;
if (!safe_add(&end_offset, offset, size)) {
return nullptr;
}
if (!safe_add(&end_offset, end_offset, page_offset(offset))) {
return nullptr;
}
size_t map_size = static_cast<size_t>(end_offset - page_min);
uint8_t* map_start = static_cast<uint8_t*>(
mmap(nullptr, map_size, PROT_READ, MAP_PRIVATE, fd, page_min));
if (map_start == MAP_FAILED) {
return nullptr;
}
return map_start + page_offset(offset);
}
ElfW(Addr) get_export_func(const char* path, const char* func_name) {
struct stat sb;
int fd = open(path, O_RDONLY);
if (fd < 0) {
return 0;
}
if (fstat(fd, &sb) < 0) {
close(fd);
return 0;
}
void* base = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (base == MAP_FAILED) {
close(fd);
return 0;
}
ElfW(Ehdr) header;
memcpy(&header, base, sizeof(header));
size_t shdr_size = header.e_shnum * sizeof(ElfW(Shdr));
ElfW(Shdr)* shdr_table = static_cast<ElfW(Shdr)*>(malloc(shdr_size));
memcpy(shdr_table, static_cast<char*>(base) + header.e_shoff, shdr_size);
char* shstrtab = static_cast<char*>(base) + shdr_table[header.e_shstrndx].sh_offset;
void* symtab = nullptr;
char* strtab = nullptr;
uint32_t symtab_size = 0;
for (size_t i = 0; i < header.e_shnum; ++i) {
const ElfW(Shdr)* shdr = &shdr_table[i];
char* section_name = shstrtab + shdr->sh_name;
if (strcmp(section_name, ".symtab") == 0) {
symtab = static_cast<char*>(base) + shdr->sh_offset;
symtab_size = shdr->sh_size;
}
if (strcmp(section_name, ".strtab") == 0) {
strtab = static_cast<char*>(base) + shdr->sh_offset;
}
if (strtab && symtab) {
break;
}
}
ElfW(Addr) result = 0;
if (symtab && strtab) {
ElfW(Sym)* sym_table = static_cast<ElfW(Sym)*>(symtab);
int sym_num = symtab_size / sizeof(ElfW(Sym));
for (int i = 0; i < sym_num; i++) {
const ElfW(Sym)* sym = &sym_table[i];
char* sym_name = strtab + sym->st_name;
if (strstr(sym_name, func_name)) {
result = sym->st_value;
break;
}
}
}
free(shdr_table);
munmap(base, sb.st_size);
close(fd);
return result;
}
}