diff --git a/elfpatch.c b/elfpatch.c index 8447257..fe2c6cb 100644 --- a/elfpatch.c +++ b/elfpatch.c @@ -2,47 +2,136 @@ #include #include #include +#include #include #include #include +#include +#include +#include + +struct elf_section { + GElf_Shdr section_header; + Elf_Scn *scn; + char *name; +}; + +struct elfpatch { + uint32_t magic; + int fd; + Elf *elf; + GElf_Ehdr ehdr; + int class; + SlList *sections; +}; + +#define ELFPATCH_MAGIC 0x8545637Aul + +#define is_elfpatch_struct(x) ((x) && (x)->magic == (ELFPATCH_MAGIC)) + +#define ret_if_ep_err(ep) do { \ + if (!is_elfpatch_struct((ep))) { \ + return; \ + } \ + } while(0) + +#define ret_val_if_ep_err(ep, val) do { \ + if (!is_elfpatch_struct((ep))) { \ + return (val); \ + } \ + } while(0) #define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__); -int elf_patch_open(struct elfpatch *ep, const char *path) +static void free_elf_section_element(struct elf_section *sec) { - int fd; - Elf *elf; - - if (!ep || !path) - return -1000; - - memset(ep, 0, sizeof(struct elfpatch)); - - fd = open(path, O_RDWR, 0); - if (fd < 0) { - print_err("Error opening file: %s\n", path); - return -1; + if (sec) { + free(sec->name); + free(sec); } - elf = elf_begin(fd, ELF_C_RDWR, NULL); - if (!elf) { - close(fd); - print_err("[LIBELF] %s\n", elf_errmsg(-1)); - return -1; - } - - ep->fd = fd; - ep->elf = elf; - - return 0; } -void elf_patch_print_stats(const struct elfpatch *ep) +static const char *section_type_to_str(Elf64_Word type) +{ + switch (type) { + case SHT_NULL: + return "NULL"; + case SHT_PROGBITS: + return "PROGBITS"; + case SHT_SYMTAB: + return "SYMTAB"; + case SHT_STRTAB: + return "STRTAB"; + case SHT_NOBITS: + return "NOBITS"; + case SHT_ARM_EXIDX: + return "ARM_EXIDX"; + case SHT_INIT_ARRAY: + return "INIT_ARRAY"; + case SHT_FINI_ARRAY: + return "FINI_ARRAY"; + default: + break; + } + return "unknown"; +} + +static SlList *elf_patch_get_sections(elfpatch_handle_t *ep) +{ + SlList *ret = NULL; + Elf_Scn *scn; + struct elf_section *sec; + char *name; + size_t shstrndx; + + ret_val_if_ep_err(ep, NULL); + + if (ep->sections) + sl_list_free_full(ret, (void (*)(void *))free_elf_section_element); + ep->sections = NULL; + + if (elf_getshdrstrndx (ep->elf , &shstrndx) != 0) { + print_err("ELF error: %s\n", elf_errmsg(-1)); + goto ret_free_section_list; + } + + scn = NULL; + while ((scn = elf_nextscn(ep->elf, scn)) != NULL) { + sec = (struct elf_section *)calloc(1u, sizeof(struct elf_section)); + sec->name = NULL; + sec->scn = scn; + ret = sl_list_append(ret, sec); + if (gelf_getshdr(scn, &sec->section_header) != &sec->section_header) { + print_err("Error reading section header: %s\n", elf_errmsg(-1)); + goto ret_free_section_list; + } + name = elf_strptr(ep->elf, shstrndx, sec->section_header.sh_name); + if (name) { + print_debug("[SEC] [%s] %s | %zu bytes at 0x%x (File offset: 0x%x) \n", + section_type_to_str(sec->section_header.sh_type), + name, (size_t)sec->section_header.sh_size, + sec->section_header.sh_addr, + sec->section_header.sh_offset); + sec->name = strdup(name); + } + } + + ep->sections = ret; + + return ret; + +ret_free_section_list: + sl_list_free_full(ret, (void (*)(void *))free_elf_section_element); + ret = NULL; + return ret; +} + +static int elf_patch_update_info(elfpatch_handle_t *ep) { Elf_Kind ek; const char *type_string = "unrecognized"; - if (!ep || !ep->elf) - return; + ret_val_if_ep_err(ep, -1001); ek = elf_kind(ep->elf); @@ -58,10 +147,83 @@ void elf_patch_print_stats(const struct elfpatch *ep) break; } print_debug("ELF File Type: %s\n", type_string); + + if (ek != ELF_K_ELF) + return -1; + + gelf_getehdr(ep->elf, &ep->ehdr); + ep->class = gelf_getclass(ep->elf); + + switch (ep->class) { + case ELFCLASS32: + print_debug("ELF class: 32 bit\n"); + break; + case ELFCLASS64: + print_debug("ELF class: 64 bit\n"); + break; + default: + print_err("Unsupported ELF class: %d\n", ep->class); + return -1; + } + + if (!elf_patch_get_sections(ep)) { + print_err("No sections in file.\n"); + return -1; + } + + + + return 0; } -void elf_patch_close(struct elfpatch *ep) +elfpatch_handle_t *elf_patch_open(const char *path) { + struct elfpatch *ep; + + if (!path) { + print_err("Internal error while opeing ELF file. No path specified\n"); + return NULL; + } + + ep = (struct elfpatch *)calloc(1u, sizeof(struct elfpatch)); + ep->magic = ELFPATCH_MAGIC; + + ep->fd = open(path, O_RDWR, 0); + if (ep->fd < 0) { + print_err("Error opening file: %s\n", path); + goto free_struct; + } + ep->elf = elf_begin(ep->fd, ELF_C_RDWR, NULL); + if (!ep->elf) { + print_err("[LIBELF] %s\n", elf_errmsg(-1)); + goto close_fd; + } + + if (elf_patch_update_info(ep)) { + print_err("File malformatted. Cannot use for CRC patching\n"); + goto close_elf; + } + + return (elfpatch_handle_t *)ep; +close_elf: + if (ep->elf) { + elf_end(ep->elf); + ep->elf = NULL; + } +close_fd: + if (ep->fd > 0) { + close(ep->fd); + } +free_struct: + free(ep); + ep = NULL; + return (elfpatch_handle_t *)ep; +} + +void elf_patch_close_and_free(elfpatch_handle_t *ep) +{ + ret_if_ep_err(ep); + if (!ep) return; if (ep->elf) @@ -70,6 +232,12 @@ void elf_patch_close(struct elfpatch *ep) if (ep->fd > 0) close(ep->fd); + if (ep->sections) + sl_list_free_full(ep->sections, (void (*)(void *))free_elf_section_element); + ep->sections = NULL; + ep->elf = NULL; ep->fd = 0; + + free(ep); } diff --git a/include/patchelfcrc/elfpatch.h b/include/patchelfcrc/elfpatch.h index 101511d..f9dd808 100644 --- a/include/patchelfcrc/elfpatch.h +++ b/include/patchelfcrc/elfpatch.h @@ -1,17 +1,12 @@ #ifndef _ELFPATCH_H_ #define _ELFPATCH_H_ -#include +#include -struct elfpatch { - int fd; - Elf *elf; -}; +typedef struct elfpatch elfpatch_handle_t; -int elf_patch_open(struct elfpatch *ep, const char *path); +elfpatch_handle_t *elf_patch_open(const char *path); -void elf_patch_print_stats(const struct elfpatch *ep); - -void elf_patch_close(struct elfpatch *ep); +void elf_patch_close_and_free(elfpatch_handle_t *ep); #endif /* _ELFPATCH_H_ */ diff --git a/include/patchelfcrc/reporting.h b/include/patchelfcrc/reporting.h index d32ac58..b63762b 100644 --- a/include/patchelfcrc/reporting.h +++ b/include/patchelfcrc/reporting.h @@ -1,10 +1,14 @@ #ifndef _REPORTING_H_ #define _REPORTING_H_ +#include + #define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__); void print_debug(const char *fmt, ...); void reporting_enable_verbose(void); +bool reporting_get_verbosity(void); + #endif /* _REPORTING_H_ */ diff --git a/main.c b/main.c index 92904e3..ce6fc6c 100644 --- a/main.c +++ b/main.c @@ -242,7 +242,7 @@ int main(int argc, char **argv) { struct crc_calc crc; struct command_line_options cmd_opts; - struct elfpatch ep; + elfpatch_handle_t *ep; prepare_default_opts(&cmd_opts); parse_cmdline_options(&argc, &argv, &cmd_opts); @@ -275,11 +275,9 @@ int main(int argc, char **argv) elf_version(EV_CURRENT); /* Open the ELF file */ - elf_patch_open(&ep, cmd_opts.elf_path); + ep = elf_patch_open(cmd_opts.elf_path); - elf_patch_print_stats(&ep); - - elf_patch_close(&ep); + elf_patch_close_and_free(ep); crc_destroy(&crc); free_cmds: diff --git a/reporting.c b/reporting.c index 14fe2ad..24cbcbf 100644 --- a/reporting.c +++ b/reporting.c @@ -20,3 +20,8 @@ void reporting_enable_verbose(void) { global_verbosity_state = true; } + +bool reporting_get_verbosity(void) +{ + return global_verbosity_state; +}