From 57b47cec64a343d690c3964714ecafa93791fd9a Mon Sep 17 00:00:00 2001 From: Kasper Date: Mon, 21 Apr 2025 23:55:14 +0300 Subject: [PATCH] Collect dynamic symbols from patch --- src/common.h | 1 + src/filewatcher/filewatcher.c | 6 +- src/hiload.c | 24 +++--- src/moduler/elf.c | 46 +++++++--- src/moduler/elf.h | 7 +- src/moduler/moduler.c | 153 ++++++++++++++++++++++++++++++++-- src/symbols.c | 31 +++++-- src/symbols.h | 52 +++++++++--- src/types.h | 1 - 9 files changed, 269 insertions(+), 52 deletions(-) diff --git a/src/common.h b/src/common.h index 9fa02f1..6f799c2 100644 --- a/src/common.h +++ b/src/common.h @@ -9,5 +9,6 @@ static inline u32 has_mask(u32 flags, u32 mask) { return flags & mask; } #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0]))) +#define HIOK(res) ((res) == HILOAD_OK) #endif // COMMON_H_ diff --git a/src/filewatcher/filewatcher.c b/src/filewatcher/filewatcher.c index 302ebc9..c6b8250 100644 --- a/src/filewatcher/filewatcher.c +++ b/src/filewatcher/filewatcher.c @@ -184,7 +184,7 @@ hiFileWatcher *hi_file_watcher_create() { memset(fw, 0, sizeof(hiFileWatcher)); if (fw) { - if (!HILOADRES(file_watcher_ctx_init(&fw->context))) { + if (!HIOK(file_watcher_ctx_init(&fw->context))) { sc_log_error("Failed to initialize watch paths\n"); if (fw->context.fd == -1) { sc_log_error("Couldn't initialize inotify\n"); @@ -213,7 +213,7 @@ HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename, mtx_lock(&fw->mutex); - if (!HILOADRES(file_watch_add(&fw->context, flags, filename))) { + if (!HIOK(file_watch_add(&fw->context, flags, filename))) { mtx_unlock(&fw->mutex); return HILOAD_FAIL; } @@ -240,7 +240,7 @@ HiloadResult hi_file_watcher_remove(struct hiFileWatcher *fw, } mtx_lock(&fw->mutex); - if (!HILOADRES(file_watch_remove(&fw->context, filename))) { + if (!HIOK(file_watch_remove(&fw->context, filename))) { mtx_unlock(&fw->mutex); return HILOAD_FAIL; } diff --git a/src/hiload.c b/src/hiload.c index b8abac0..1f89103 100644 --- a/src/hiload.c +++ b/src/hiload.c @@ -1,6 +1,7 @@ #include "hiload/hiload.h" #include "array/array.h" +#include "common.h" #include "filewatcher/filewatch_context.h" #include "filewatcher/filewatcher.h" #include "logger/logger.h" @@ -8,7 +9,6 @@ #include "moduler/moduler.h" #include "string/string.h" #include "symbols.h" -#include "types.h" #include #include @@ -71,8 +71,8 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, sc_array_at(&context.enabled_modules, i) = module.name; // Add filewatcher - if (!HILOADRES(hi_file_watcher_add(context.filewatcher, modpath, - HI_FILE_ALL_EVENTS))) { + if (!HIOK(hi_file_watcher_add(context.filewatcher, modpath, + HI_FILE_ALL_EVENTS))) { log_error("Failed to set filewatcher for: '%s'\n", modpath); } else { log_info("Watching file: %s\n", modpath); @@ -81,7 +81,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, } } else { module.name = strdup(modname); - log_error("Couldn't load dlinfo for %s: %s\n", module.name, dlerror()); + log_warn("Couldn't load dlinfo for %s: %s\n", module.name, dlerror()); } HiModuleArray *modules = (HiModuleArray *)data; @@ -95,7 +95,7 @@ static void module_infos_free(HiModuleArray *modules) { return; for (size_t i = 0; i < sc_array_size(modules); i++) { - free((char*)sc_array_at(modules, i).name); + free((char *)sc_array_at(modules, i).name); } free(modules); @@ -115,7 +115,8 @@ HiloadResult gather_module_infos(HiModuleArray *modules) { return HILOAD_OK; } -static HiModuleData *get_module_by_path(const char *path, HiModuleArray *modules) { +static HiModuleData *get_module_by_path(const char *path, + HiModuleArray *modules) { for (size_t i = 0; i < sc_array_size(modules); i++) { HiModuleData *module = &sc_array_at(modules, i); @@ -149,8 +150,8 @@ static void handle_events(struct hiFileWatcher *fw, HiModuleArray *modules) { } } -static const char* find_string_from_array(const char *needle, - const struct sc_array_str *haystack) { +static const char *find_string_from_array(const char *needle, + const struct sc_array_str *haystack) { for (size_t i = 0; i < sc_array_size(haystack); i++) { if (strcmp(needle, sc_array_at(haystack, i)) == 0) { @@ -171,11 +172,12 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) { if (module->state == HI_MODULE_STATE_DIRTY) { // Operate only if the module is marked as operatable - const char *module_name = find_string_from_array(module->name, &context->enabled_modules); + const char *module_name = + find_string_from_array(module->name, &context->enabled_modules); if (module_name) { log_info("Reloading %s...\n", module_name); - if (moduler_reload(module, &context->memory_regions) != HILOAD_OK) { + if (!HIOK(moduler_reload(module, &context->memory_regions))) { ret = HILOAD_FAIL; log_error("Failed loading: %s\n", module->name); } @@ -218,7 +220,7 @@ int hi_init(unsigned n, const char **enabled_modules) { } HiloadResult re = gather_module_infos(&context.modules); - if (re != HILOAD_OK) { + if (re != HILOAD_OK) { log_error("Failed to gather module infos.\n"); return 1; } diff --git a/src/moduler/elf.c b/src/moduler/elf.c index 3f697bd..16b9709 100644 --- a/src/moduler/elf.c +++ b/src/moduler/elf.c @@ -4,17 +4,43 @@ #include "types.h" #include +#include #include #include -void *hi_elf_load_module(void *address, size_t n) { +void *hi_elf_find_dynamic_segment(void *module_base, size_t n, Elf **elf_ret) { - Elf *elf = elf_memory(address, n); - Elf_Kind modkind = elf_kind(elf); - log_debug("kind: %u\n", modkind); + Elf *elf = elf_memory(module_base, n); - elf_end(elf); - return address; + size_t phdrnum = 0; + int err = elf_getphdrnum(elf, &phdrnum); + if (err == -1) { + log_error("%s\n", elf_errmsg(elf_errno())); + return NULL; + } + + void *dyn_addr = NULL; + + for (size_t i=0; i < phdrnum; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) != &phdr) { + log_error("Failed to find program headers: %s\n", elf_errmsg(elf_errno())); + continue; + } + + if (phdr.p_type == PT_DYNAMIC) { + dyn_addr = module_base + phdr.p_vaddr; + break; + } + } + + if (elf_ret) { + *elf_ret = elf; + } else { + elf_end(elf); + } + + return dyn_addr; } void hi_elf_print_module_from_memory(void *address, size_t size) { @@ -32,7 +58,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) { for (size_t i = 0; i < phdrnum; ++i) { Elf64_Phdr *p = phdr + i; - log_debug("segment type: %s\n", segment_type_to_str(p->p_type)); + log_debug("segment type: %s\n", hi_elf_segtostr(p->p_type)); size_t segment_size = p->p_memsz; void *segment_start = address + p->p_vaddr; @@ -53,7 +79,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) { if (p->p_type == PT_DYNAMIC) { Elf64_Dyn *dyn = (Elf64_Dyn *)segment_start; while ((void *)dyn < segment_end) { - log_debug(" dyn type: %s\n", dyn_type_to_str(dyn->d_tag)); + log_debug(" dyn type: %s\n", hi_elf_dyntostr(dyn->d_tag)); if (dyn->d_tag == DT_STRTAB) { strtab = (void *)dyn->d_un.d_ptr; @@ -101,7 +127,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) { case (type): \ return #type -const char *dyn_type_to_str(unsigned type) { +const char *hi_elf_dyntostr(unsigned type) { // clang-format off switch (type) { TYPE_TO_STR(DT_NULL); @@ -184,7 +210,7 @@ const char *dyn_type_to_str(unsigned type) { // clang-format on } -const char *segment_type_to_str(unsigned type) { +const char *hi_elf_segtostr(unsigned type) { // clang-format off switch (type) { TYPE_TO_STR(PT_NULL); diff --git a/src/moduler/elf.h b/src/moduler/elf.h index cdb8abc..eb24be9 100644 --- a/src/moduler/elf.h +++ b/src/moduler/elf.h @@ -6,10 +6,9 @@ #include #include -void *hi_elf_load_module(void *address, size_t n); -void hi_elf_print_module_from_memory(void *address, size_t size); +void *hi_elf_find_dynamic_segment(void *module_base, size_t n, Elf **elf); -const char *dyn_type_to_str(unsigned type); -const char *segment_type_to_str(unsigned type); +const char *hi_elf_dyntostr(unsigned type); +const char *hi_elf_segtostr(unsigned type); #endif diff --git a/src/moduler/moduler.c b/src/moduler/moduler.c index ca944f6..80a7436 100644 --- a/src/moduler/moduler.c +++ b/src/moduler/moduler.c @@ -5,24 +5,164 @@ #include "memory.h" #include "moduler/elf.h" #include "string/string.h" +#include "symbols.h" #include "types.h" #include +#include +#include +#include #include #include #include #include +#include -static HiloadResult moduler_apply_patch(void *address, size_t n) { +static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols, + const char *patch_name, + void *module_base) { + sc_array_clear(symbols); HiloadResult ret = HILOAD_FAIL; - Elf *elf = elf_memory(address, n); + int patchfd = open(patch_name, O_RDONLY); + if (patchfd == -1) { + log_error("Failed to open %s: %s\n", patch_name, strerror(errno)); + return HILOAD_FAIL; + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + log_error("Failed to initialize libelf\n"); + close(patchfd); + return HILOAD_FAIL; + } + + Elf *elf = elf_begin(patchfd, ELF_C_READ, NULL); + if (!elf) { + log_error("Failed to open elf file: %s\n", elf_errmsg(elf_errno())); + goto cleanup; + } + + if (elf_kind(elf) != ELF_K_ELF) { + log_error("Not a valid ELF file\n"); + goto cleanup; + } + + // Get ELF header + GElf_Ehdr ehdr; + if (gelf_getehdr(elf, &ehdr) == NULL) { + log_error("Failed to get ELF header: %s\n", elf_errmsg(elf_errno())); + goto cleanup; + } + + // Iterate through sections to find symbol tables + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn(elf, scn)) != NULL) { + GElf_Shdr shdr; + if (gelf_getshdr(scn, &shdr) != &shdr) { + log_error("Failed to get section header: %s\n", elf_errmsg(elf_errno())); + continue; + } + + // Look for dynamic symbol table (SHT_DYNSYM) + if (shdr.sh_type == SHT_DYNSYM) { + // Get the string table for symbol names + Elf_Scn *str_scn = elf_getscn(elf, shdr.sh_link); + if (!str_scn) { + log_error("Failed to get string table section: %s\n", + elf_errmsg(elf_errno())); + continue; + } + + GElf_Shdr str_shdr; + if (gelf_getshdr(str_scn, &str_shdr) != &str_shdr) { + log_error("Failed to get string table header: %s\n", + elf_errmsg(elf_errno())); + continue; + } + + // Get string table data + Elf_Data *str_data = elf_getdata(str_scn, NULL); + if (!str_data) { + log_error("Failed to get string table data: %s\n", + elf_errmsg(elf_errno())); + continue; + } + + // Get symbol table data + Elf_Data *sym_data = elf_getdata(scn, NULL); + if (!sym_data) { + log_error("Failed to get symbol table data: %s\n", + elf_errmsg(elf_errno())); + continue; + } + + // Calculate number of symbols + size_t sym_count = shdr.sh_size / shdr.sh_entsize; + + for (size_t i = 0; i < sym_count; ++i) { + GElf_Sym sym; + if (gelf_getsym(sym_data, i, &sym) != &sym) { + log_error("Failed to get symbol: %s\n", elf_errmsg(elf_errno())); + continue; + } + + const char *name = (const char *)(str_data->d_buf) + sym.st_name; + if (sym.st_name == 0 || strlen(name) == 0) { + continue; // Skip unnamed symbols + } + + // Calculate actual address (base + offset) + void *sym_addr = (void *)((uintptr_t)module_base + sym.st_value); + HiSymbolBind binding = symbol_bind_from_efi(GELF_ST_BIND(sym.st_info)); + HiSymbolType type = symbol_type_from_efi(GELF_ST_TYPE(sym.st_info)); + + if (binding == HI_SYMBOL_BIND_GLOBAL) { + HiSymbol hisym = {.name = strdup(name), + .binding = binding, + .type = type, + .address = sym_addr}; + + sc_array_add(symbols, hisym); + } + } + } + } - hi_elf_print_module_from_memory(address, n); ret = HILOAD_OK; +cleanup: elf_end(elf); + close(patchfd); + + return ret; +} + +static HiloadResult moduler_apply_module_patch(const char *module_name, const char *patch_name, + struct sc_array_memreg *memregs) { + + MemoryRegionSpan patch_memory = memory_get_module_span(memregs, patch_name); + void *patch_base = (void *)patch_memory.region_start; + + HiSymbols symbols; + symbol_init_symbols(&symbols); + + HiloadResult ret = gather_patchable_symbols(&symbols, patch_name, patch_base); + if (!HIOK(ret)) { + log_error("Failed to gather symbols for %s\n", 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; + + Elf *elf = NULL; + GElf_Phdr *dyn_sct = hi_elf_find_dynamic_segment(module_base, module_size, &elf); + (void)dyn_sct; + // TODO: cont + + symbol_term_symbols(&symbols); return ret; } @@ -34,11 +174,11 @@ HiloadResult moduler_reload(HiModuleData *module, log_debugv("Module: %s - [%p, %p]\n", module->name, memspan.region_start, memspan.region_end); - dlerror(); + dlerror(); // clear old errors char patch_name[512]; size_t written = hi_strncat_buf(sizeof(patch_name), patch_name, module->name, ".patch"); - if (!written) { + if (written == 0) { log_error("Failed to concat %s and %s\n", module->name, ".patch"); return HILOAD_FAIL; } @@ -52,13 +192,14 @@ HiloadResult moduler_reload(HiModuleData *module, 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_patch(patch_address, memspan.region_end - memspan.region_start); + moduler_apply_module_patch(module->name, patch_name, memregs); module->state = HI_MODULE_STATE_CLEAN; return HILOAD_OK; diff --git a/src/symbols.c b/src/symbols.c index 957bddf..4a2a220 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -1,12 +1,29 @@ #include "symbols.h" -#include +#include -void hi_free_symbol_info(SymbolInfos *symbols) { - for (size_t i = 0; i < symbols->names.size; i++) { - free((void *)symbols->names.elems[i]); +HiSymbolBind symbol_bind_from_efi(u32 efi_bind) { + // clang-format off + switch (efi_bind) { + case STB_LOCAL: return HI_SYMBOL_BIND_LOCAL; + case STB_GLOBAL: return HI_SYMBOL_BIND_GLOBAL; + case STB_WEAK: return HI_SYMBOL_BIND_WEAK; } - - sc_array_term(&symbols->names); - sc_array_term(&symbols->addresses); + // clang-format on + return ~0u; +} + +HiSymbolType symbol_type_from_efi(u32 efi_type) { + // clang-format off + switch (efi_type) { + case STT_NOTYPE: return HI_SYMBOL_TYPE_NOTYPE; /* Symbol type is unspecified */ + case STT_OBJECT: return HI_SYMBOL_TYPE_OBJECT; /* Symbol is a data object */ + case STT_FUNC: return HI_SYMBOL_TYPE_FUNC; /* Symbol is a code object */ + case STT_SECTION: return HI_SYMBOL_TYPE_SECTION; /* Symbol associated with a section */ + case STT_FILE: return HI_SYMBOL_TYPE_FILE; /* Symbol's name is file name */ + case STT_COMMON: return HI_SYMBOL_TYPE_COMMON; /* Symbol is a common data object */ + case STT_TLS: return HI_SYMBOL_TYPE_TLS; /* Symbol is thread-local data object*/ + } + // clang-format on + return ~0u; } diff --git a/src/symbols.h b/src/symbols.h index cfe9fa6..1d308e6 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -1,20 +1,52 @@ #ifndef SYMBOLS_H_ #define SYMBOLS_H_ -#include "memory.h" +#include "array/array.h" +#include "array/sc_array.h" #include "types.h" -#include -#include -#include +typedef enum { + HI_SYMBOL_BIND_LOCAL, + HI_SYMBOL_BIND_GLOBAL, + HI_SYMBOL_BIND_WEAK, +} HiSymbolBind; -typedef struct { - struct sc_array_str names; - struct sc_array_ptr addresses; -} SymbolInfos; +typedef enum { + HI_SYMBOL_TYPE_NOTYPE, + HI_SYMBOL_TYPE_OBJECT, + HI_SYMBOL_TYPE_FUNC, + HI_SYMBOL_TYPE_SECTION, + HI_SYMBOL_TYPE_FILE, + HI_SYMBOL_TYPE_COMMON, + HI_SYMBOL_TYPE_TLS, +} HiSymbolType; -sc_array_def(SymbolInfos, syms); +typedef struct HiSymbol { + const char *name; + HiSymbolBind binding; + HiSymbolType type; + void *address; +} HiSymbol; +sc_array_def(HiSymbol, sym); +typedef struct sc_array_sym HiSymbols; -void hi_free_symbol_info(SymbolInfos *); +static inline void symbol_free(HiSymbol *symbol) { free((char *)symbol->name); } +static inline void symbol_init_symbols(HiSymbols *symbols) { + sc_array_init(symbols); +} +static inline void symbol_clear_symbols(HiSymbols *symbols) { + for (size_t i = 0; i < sc_array_size(symbols); ++i) { + symbol_free(&sc_array_at(symbols, i)); + } + sc_array_clear(symbols); +} + +static inline void symbol_term_symbols(HiSymbols *symbols) { + symbol_clear_symbols(symbols); + sc_array_term(symbols); +} + +HiSymbolBind symbol_bind_from_efi(u32 efi_bind); +HiSymbolType symbol_type_from_efi(u32 efi_type); #endif // SYMBOLS_H_ diff --git a/src/types.h b/src/types.h index de86128..552ab07 100644 --- a/src/types.h +++ b/src/types.h @@ -22,7 +22,6 @@ typedef uint8_t bool8; typedef uint32_t bool32; typedef enum { HILOAD_FAIL = 0, HILOAD_OK } HiloadResult; -#define HILOADRES(res) ((res) == HILOAD_OK) #endif // TYPES_H_