first working reload
This commit is contained in:
@@ -177,7 +177,7 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) {
|
|||||||
if (module_name) {
|
if (module_name) {
|
||||||
log_info("Reloading %s...\n", 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;
|
ret = HILOAD_FAIL;
|
||||||
log_error("Failed loading: %s\n", module->name);
|
log_error("Failed loading: %s\n", module->name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,18 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
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,
|
static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols,
|
||||||
const char *patch_name,
|
const char *patch_name,
|
||||||
void *module_base) {
|
void *module_base) {
|
||||||
@@ -139,10 +151,137 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HiloadResult
|
static HiloadResult moduler_apply_module_patch(HiSymbols *symbols,
|
||||||
moduler_apply_module_patch(const char *module_name, const char *patch_name,
|
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) {
|
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);
|
MemoryRegionSpan patch_memory = memory_get_module_span(memregs, patch_name);
|
||||||
void *patch_base = (void *)patch_memory.region_start;
|
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;
|
return HILOAD_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegionSpan module_memory = memory_get_module_span(memregs, module_name);
|
for (size_t i = 0; i < sc_array_size(modules); ++i) {
|
||||||
void *module_base = (void *)module_memory.region_start;
|
HiModuleData mod = sc_array_at(modules, i);
|
||||||
size_t module_size = module_memory.region_end - module_memory.region_start;
|
|
||||||
|
|
||||||
ElfW(Rela) *rela = NULL;
|
// Filter system and virtual modules
|
||||||
ElfW(Sym) *symtab = NULL;
|
if (mod.name[0] != '/')
|
||||||
char *strtab = NULL;
|
continue;
|
||||||
size_t rela_size = 0;
|
if (hi_string_starts_with(mod.name, ARRLEN(mod_exclude_filter),
|
||||||
|
mod_exclude_filter))
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
ElfW(Sym)* sym = &symtab[sym_idx];
|
MemoryRegionSpan module_memory = memory_get_module_span(memregs, mod.name);
|
||||||
char* name = strtab + sym->st_name;
|
|
||||||
|
|
||||||
/* // Calculate the GOT entry address */
|
moduler_apply_module_patch(&symbols, module_memory);
|
||||||
/* void** got_entry = (void**)((char*)module_base + r->r_offset); */
|
|
||||||
|
|
||||||
/* // Check if this is a symbol we want to patch */
|
module->state = HI_MODULE_STATE_CLEAN;
|
||||||
/* 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);
|
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;
|
return HILOAD_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ sc_array_def(HiModuleData, module);
|
|||||||
|
|
||||||
typedef struct sc_array_module HiModuleArray;
|
typedef struct sc_array_module HiModuleArray;
|
||||||
|
|
||||||
HiloadResult moduler_reload(HiModuleData *module,
|
HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module,
|
||||||
struct sc_array_memreg *memregs);
|
struct sc_array_memreg *memregs);
|
||||||
|
|
||||||
#endif // MODULER_H_
|
#endif // MODULER_H_
|
||||||
|
|||||||
@@ -104,3 +104,16 @@ char *hi_string_from_file_dyn(const char *filename, size_t *nread,
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return buf;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
/**
|
/**
|
||||||
* Concatenate two strings into a buffer.
|
* Concatenate two strings into a buffer.
|
||||||
*
|
*
|
||||||
* If resulting string would be longer than buflen - 1, the resulting string in \p
|
* If resulting string would be longer than buflen - 1, the resulting string in
|
||||||
* buf is unchanged.
|
* \p buf is unchanged.
|
||||||
*
|
*
|
||||||
* @param first Null terminated character string
|
* @param first Null terminated character string
|
||||||
* @param second 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);
|
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_
|
#endif // HI_STRING_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user