Update ELF parser. Sectionr eading implemented
This commit is contained in:
		
							
								
								
									
										224
									
								
								elfpatch.c
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								elfpatch.c
									
									
									
									
									
								
							@@ -2,47 +2,136 @@
 | 
			
		||||
#include <patchelfcrc/reporting.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <libelf.h>
 | 
			
		||||
#include <gelf.h>
 | 
			
		||||
#include <linklist-lib/singly-linked-list.h>
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,12 @@
 | 
			
		||||
#ifndef _ELFPATCH_H_
 | 
			
		||||
#define _ELFPATCH_H_
 | 
			
		||||
 | 
			
		||||
#include <libelf.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
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_ */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,14 @@
 | 
			
		||||
#ifndef _REPORTING_H_
 | 
			
		||||
#define _REPORTING_H_
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#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_ */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								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:
 | 
			
		||||
 
 | 
			
		||||
@@ -20,3 +20,8 @@ void reporting_enable_verbose(void)
 | 
			
		||||
{
 | 
			
		||||
	global_verbosity_state = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool reporting_get_verbosity(void)
 | 
			
		||||
{
 | 
			
		||||
	return global_verbosity_state;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user