diff --git a/src/hiload.c b/src/hiload.c index 1f89103..9ad0b22 100644 --- a/src/hiload.c +++ b/src/hiload.c @@ -177,7 +177,7 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) { if (module_name) { log_info("Reloading %s...\n", module_name); - if (!HIOK(moduler_reload(module, &context->memory_regions))) { + if (!HIOK(moduler_reload(&context->modules, module, &context->memory_regions))) { ret = HILOAD_FAIL; log_error("Failed loading: %s\n", module->name); } diff --git a/src/moduler/moduler.c b/src/moduler/moduler.c index a0dbc7f..0413441 100644 --- a/src/moduler/moduler.c +++ b/src/moduler/moduler.c @@ -19,6 +19,18 @@ #include #include +const char *mod_exclude_filter[] = { + "/usr/", "/lib/", "/lib64/", "/bin/", "/opt/", +}; + +static void *adjust_if_relative(void *ptr, void *module_base) { + uptr p = (uptr)ptr; + if (p && (p < (uptr)module_base)) { + p = (uptr)module_base + (uptr)ptr; + } + return (void *)p; +} + static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols, const char *patch_name, void *module_base) { @@ -139,9 +151,136 @@ cleanup: return ret; } -static HiloadResult -moduler_apply_module_patch(const char *module_name, const char *patch_name, - struct sc_array_memreg *memregs) { +static HiloadResult moduler_apply_module_patch(HiSymbols *symbols, + MemoryRegionSpan module_memory) { + + void *module_base = (void *)module_memory.region_start; + size_t module_size = module_memory.region_end - module_memory.region_start; + + void *plt = NULL; + ElfW(Rela) *jmprel = NULL; + ElfW(Rela) *rela = NULL; + ElfW(Sym) *symtab = NULL; + char *strtab = NULL; + size_t pltsz = 0; + size_t relasz = 0; + size_t plt_type = 0; + + Elf *elf = NULL; + ElfW(Dyn) *dyn_sct = + hi_elf_find_dynamic_segment(module_base, module_size, &elf); + + for (ElfW(Dyn) *d = dyn_sct; d->d_tag != DT_NULL; d++) { + log_debug("%s\n", hi_elf_dyntostr(d->d_tag)); + switch (d->d_tag) { + case DT_RELASZ: + relasz = d->d_un.d_val; + break; + case DT_RELA: + rela = (ElfW(Rela) *)d->d_un.d_ptr; + break; + case DT_PLTGOT: + plt = (ElfW(Rela) *)d->d_un.d_ptr; + break; + case DT_PLTRELSZ: + pltsz = d->d_un.d_val; + break; + case DT_PLTREL: + plt_type = d->d_un.d_val; + break; + case DT_JMPREL: + jmprel = (ElfW(Rela) *)d->d_un.d_ptr; + break; + case DT_SYMTAB: + symtab = (ElfW(Sym) *)d->d_un.d_ptr; + break; + case DT_STRTAB: + strtab = (char *)d->d_un.d_ptr; + break; + } + } + + // Adjust relative pointers by adding the module base address + plt = adjust_if_relative(plt, module_base); + rela = adjust_if_relative(rela, module_base); + symtab = adjust_if_relative(symtab, module_base); + strtab = adjust_if_relative(strtab, module_base); + + if ((!rela && !jmprel) || !symtab || !strtab || relasz == 0) { + log_error("Missing required dynamic information\n"); + elf_end(elf); + return HILOAD_FAIL; + } + + int found_count = 0; + size_t rela_count = relasz / sizeof(ElfW(Rela)); + + printf("Processing %zu relocations\n", rela_count); + + size_t num_symbols = sc_array_size(symbols); + ElfW(Rela) *r = NULL; + for (size_t i = 0; i < rela_count; i++) { + + r = jmprel ? &jmprel[i] : &rela[i]; + int sym_idx = GELF_R_SYM(r->r_info); + int rel_type = GELF_R_TYPE(r->r_info); + + // We're only interested in JMP_SLOT relocations (GOT entries for functions) + if (rel_type != R_X86_64_JUMP_SLOT && rel_type != R_386_JMP_SLOT) { + continue; + } + + ElfW(Sym) *sym = &symtab[sym_idx]; + char *name = strtab + sym->st_name; + + // Calculate the GOT entry address + void **got_entry = (void **)((char *)module_base + r->r_offset); + + // Check if this is a symbol we want to patch + for (size_t j = 0; j < num_symbols; j++) { + HiSymbol *sym = &sc_array_at(symbols, j); + if (strcmp(sym->name, name) == 0) { + sym->got_entry = got_entry; + sym->orig_address = *got_entry; // Save the original function + + *got_entry = sym->address; + printf("Found GOT entry for '%s' at %p (points to %p)\n", name, + got_entry, *got_entry); + + found_count++; + break; + } + } + } + + elf_end(elf); + return HILOAD_OK; +} + +HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, + struct sc_array_memreg *memregs) { + + dlerror(); // clear old errors + char patch_name[512]; + size_t written = + hi_strncat_buf(sizeof(patch_name), patch_name, module->name, ".patch"); + if (written == 0) { + log_error("Failed to concat %s and %s\n", module->name, ".patch"); + return HILOAD_FAIL; + } + + // Load patch + log_debug("Opening: %s\n", patch_name); + + void *new_handle = dlopen(patch_name, RTLD_LAZY); + if (!new_handle) { + log_error("Couldn't load: %s\n", dlerror()); + module->state = HI_MODULE_STATE_CLEAN; + return HILOAD_FAIL; + } + + // refresh before using + read_memory_maps_self(memregs); MemoryRegionSpan patch_memory = memory_get_module_span(memregs, patch_name); void *patch_base = (void *)patch_memory.region_start; @@ -155,138 +294,24 @@ moduler_apply_module_patch(const char *module_name, const char *patch_name, return HILOAD_FAIL; } - MemoryRegionSpan module_memory = memory_get_module_span(memregs, module_name); - void *module_base = (void *)module_memory.region_start; - size_t module_size = module_memory.region_end - module_memory.region_start; + for (size_t i = 0; i < sc_array_size(modules); ++i) { + HiModuleData mod = sc_array_at(modules, i); - ElfW(Rela) *rela = NULL; - ElfW(Sym) *symtab = NULL; - char *strtab = NULL; - size_t rela_size = 0; + // Filter system and virtual modules + if (mod.name[0] != '/') + continue; + if (hi_string_starts_with(mod.name, ARRLEN(mod_exclude_filter), + mod_exclude_filter)) + continue; - Elf *elf = NULL; - ElfW(Dyn) *dyn_sct = - hi_elf_find_dynamic_segment(module_base, module_size, &elf); - for (ElfW(Dyn) *d = dyn_sct; d->d_tag != DT_NULL; d++) { - switch (d->d_tag) { - case DT_JMPREL: - rela = (ElfW(Rela) *)d->d_un.d_ptr; - break; - case DT_PLTRELSZ: - rela_size = d->d_un.d_val; - break; - case DT_SYMTAB: - symtab = (ElfW(Sym)*)d->d_un.d_ptr; - break; - case DT_STRTAB: - strtab = (char *)d->d_un.d_ptr; - break; - } + MemoryRegionSpan module_memory = memory_get_module_span(memregs, mod.name); + + moduler_apply_module_patch(&symbols, module_memory); + + module->state = HI_MODULE_STATE_CLEAN; } - // Adjust relative pointers by adding the module base address - if (rela && ((void *)rela < module_base || - (void *)rela >= (void *)((char *)module_base + module_size))) { - rela = (ElfW(Rela) *)((char *)module_base + (uintptr_t)rela); - } - - if (symtab && - ((void *)symtab < module_base || - (void *)symtab >= (void *)((char *)module_base + module_size))) { - symtab = (ElfW(Sym) *)((char *)module_base + (uintptr_t)symtab); - } - - if (strtab && - ((void *)strtab < module_base || - (void *)strtab >= (void *)((char *)module_base + module_size))) { - strtab = (char *)module_base + (uintptr_t)strtab; - } - - if (!rela || !symtab || !strtab || rela_size == 0) { - log_error("Missing required dynamic information\n"); - elf_end(elf); - return HILOAD_FAIL; - } - - - // Process relocations to find GOT entries - int found_count = 0; - size_t rela_count = rela_size / sizeof(ElfW(Rela)); - - printf("Processing %zu relocations\n", rela_count); - - size_t num_symbols = 0; - for (size_t i = 0; i < rela_count; i++) { - ElfW(Rela)* r = &rela[i]; - int sym_idx = ElfW(R_SYM)(r->r_info); - int rel_type = ElfW(R_TYPE)(r->r_info); - - // We're only interested in JMP_SLOT relocations (GOT entries for functions) - if (rel_type != R_X86_64_JUMP_SLOT && rel_type != R_386_JMP_SLOT) { - continue; - } - - ElfW(Sym)* sym = &symtab[sym_idx]; - char* name = strtab + sym->st_name; - - /* // Calculate the GOT entry address */ - /* void** got_entry = (void**)((char*)module_base + r->r_offset); */ - - /* // Check if this is a symbol we want to patch */ - /* for (int j = 0; j < num_symbols; j++) { */ - /* if (strcmp(symbols[j].name, name) == 0) { */ - /* symbols[j].got_entry = got_entry; */ - /* symbols[j].orig_addr = *got_entry; // Save the original function pointer */ - - /* printf("Found GOT entry for '%s' at %p (points to %p)\n", */ - /* name, got_entry, *got_entry); */ - - /* found_count++; */ - /* break; */ - /* } */ - /* } */ - } - symbol_term_symbols(&symbols); - elf_end(elf); - return ret; -} - -HiloadResult moduler_reload(HiModuleData *module, - struct sc_array_memreg *memregs) { - - MemoryRegionSpan memspan = memory_get_module_span(memregs, module->name); - log_debugv("Module: %s - [%p, %p]\n", module->name, memspan.region_start, - memspan.region_end); - - dlerror(); // clear old errors - char patch_name[512]; - size_t written = - hi_strncat_buf(sizeof(patch_name), patch_name, module->name, ".patch"); - if (written == 0) { - log_error("Failed to concat %s and %s\n", module->name, ".patch"); - return HILOAD_FAIL; - } - - log_debug("Opening: %s\n", patch_name); - - void *new_handle = dlopen(patch_name, RTLD_NOW); - if (!new_handle) { - log_error("Couldn't load: %s\n", dlerror()); - module->state = HI_MODULE_STATE_CLEAN; - return HILOAD_FAIL; - } - - // refresh before using - read_memory_maps_self(memregs); - memspan = memory_get_module_span(memregs, patch_name); - - void *patch_address = (void *)memspan.region_start; - log_debug("patch address: %p\n", patch_address); - - moduler_apply_module_patch(module->name, patch_name, memregs); - - module->state = HI_MODULE_STATE_CLEAN; return HILOAD_OK; } diff --git a/src/moduler/moduler.h b/src/moduler/moduler.h index efe39f7..a9026d7 100644 --- a/src/moduler/moduler.h +++ b/src/moduler/moduler.h @@ -23,7 +23,7 @@ sc_array_def(HiModuleData, module); typedef struct sc_array_module HiModuleArray; -HiloadResult moduler_reload(HiModuleData *module, +HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, struct sc_array_memreg *memregs); #endif // MODULER_H_ diff --git a/src/string/string.c b/src/string/string.c index 7021529..39f8d24 100644 --- a/src/string/string.c +++ b/src/string/string.c @@ -104,3 +104,16 @@ char *hi_string_from_file_dyn(const char *filename, size_t *nread, fclose(f); return buf; } + +const char *hi_string_starts_with(const char path[static 1], size_t listn, const char *pathlist[listn]) { + + if (!pathlist) return path; + size_t pathlen = strlen(path); + for (size_t i=0; i < listn; ++i) { + size_t len = MIN(strlen(pathlist[i]), pathlen); + if (strncmp(path, pathlist[i], len) == 0) { + return pathlist[i]; + } + } + return NULL; +} diff --git a/src/string/string.h b/src/string/string.h index 9ebd43e..f6f7d36 100644 --- a/src/string/string.h +++ b/src/string/string.h @@ -6,8 +6,8 @@ /** * Concatenate two strings into a buffer. * - * If resulting string would be longer than buflen - 1, the resulting string in \p - * buf is unchanged. + * If resulting string would be longer than buflen - 1, the resulting string in + * \p buf is unchanged. * * @param first Null terminated character string * @param second Null terminated character string @@ -39,4 +39,7 @@ char *hi_string_from_file_dyn(const char *filename, size_t *nread, size_t nmax); */ int hi_path_has_filename(const char *path, const char *filename); +const char *hi_string_starts_with(const char path[static 1], size_t listn, + const char *pathlist[listn]); + #endif // HI_STRING_H_