Update ELF parser. Sectionr eading implemented
This commit is contained in:
parent
fb5f527f45
commit
0278cb19d4
220
elfpatch.c
220
elfpatch.c
@ -2,47 +2,136 @@
|
|||||||
#include <patchelfcrc/reporting.h>
|
#include <patchelfcrc/reporting.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.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__);
|
#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;
|
if (sec) {
|
||||||
Elf *elf;
|
free(sec->name);
|
||||||
|
free(sec);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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;
|
static const char *section_type_to_str(Elf64_Word type)
|
||||||
ep->elf = elf;
|
{
|
||||||
|
switch (type) {
|
||||||
return 0;
|
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";
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf_patch_print_stats(const struct elfpatch *ep)
|
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;
|
Elf_Kind ek;
|
||||||
const char *type_string = "unrecognized";
|
const char *type_string = "unrecognized";
|
||||||
|
|
||||||
if (!ep || !ep->elf)
|
ret_val_if_ep_err(ep, -1001);
|
||||||
return;
|
|
||||||
|
|
||||||
ek = elf_kind(ep->elf);
|
ek = elf_kind(ep->elf);
|
||||||
|
|
||||||
@ -58,10 +147,83 @@ void elf_patch_print_stats(const struct elfpatch *ep)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
print_debug("ELF File Type: %s\n", type_string);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf_patch_close(struct elfpatch *ep)
|
if (!elf_patch_get_sections(ep)) {
|
||||||
|
print_err("No sections in file.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
if (!ep)
|
||||||
return;
|
return;
|
||||||
if (ep->elf)
|
if (ep->elf)
|
||||||
@ -70,6 +232,12 @@ void elf_patch_close(struct elfpatch *ep)
|
|||||||
if (ep->fd > 0)
|
if (ep->fd > 0)
|
||||||
close(ep->fd);
|
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->elf = NULL;
|
||||||
ep->fd = 0;
|
ep->fd = 0;
|
||||||
|
|
||||||
|
free(ep);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
#ifndef _ELFPATCH_H_
|
#ifndef _ELFPATCH_H_
|
||||||
#define _ELFPATCH_H_
|
#define _ELFPATCH_H_
|
||||||
|
|
||||||
#include <libelf.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct elfpatch {
|
typedef struct elfpatch elfpatch_handle_t;
|
||||||
int fd;
|
|
||||||
Elf *elf;
|
|
||||||
};
|
|
||||||
|
|
||||||
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_and_free(elfpatch_handle_t *ep);
|
||||||
|
|
||||||
void elf_patch_close(struct elfpatch *ep);
|
|
||||||
|
|
||||||
#endif /* _ELFPATCH_H_ */
|
#endif /* _ELFPATCH_H_ */
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#ifndef _REPORTING_H_
|
#ifndef _REPORTING_H_
|
||||||
#define _REPORTING_H_
|
#define _REPORTING_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
|
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
|
||||||
|
|
||||||
void print_debug(const char *fmt, ...);
|
void print_debug(const char *fmt, ...);
|
||||||
|
|
||||||
void reporting_enable_verbose(void);
|
void reporting_enable_verbose(void);
|
||||||
|
|
||||||
|
bool reporting_get_verbosity(void);
|
||||||
|
|
||||||
#endif /* _REPORTING_H_ */
|
#endif /* _REPORTING_H_ */
|
||||||
|
8
main.c
8
main.c
@ -242,7 +242,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
struct crc_calc crc;
|
struct crc_calc crc;
|
||||||
struct command_line_options cmd_opts;
|
struct command_line_options cmd_opts;
|
||||||
struct elfpatch ep;
|
elfpatch_handle_t *ep;
|
||||||
|
|
||||||
prepare_default_opts(&cmd_opts);
|
prepare_default_opts(&cmd_opts);
|
||||||
parse_cmdline_options(&argc, &argv, &cmd_opts);
|
parse_cmdline_options(&argc, &argv, &cmd_opts);
|
||||||
@ -275,11 +275,9 @@ int main(int argc, char **argv)
|
|||||||
elf_version(EV_CURRENT);
|
elf_version(EV_CURRENT);
|
||||||
|
|
||||||
/* Open the ELF file */
|
/* 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_and_free(ep);
|
||||||
|
|
||||||
elf_patch_close(&ep);
|
|
||||||
|
|
||||||
crc_destroy(&crc);
|
crc_destroy(&crc);
|
||||||
free_cmds:
|
free_cmds:
|
||||||
|
@ -20,3 +20,8 @@ void reporting_enable_verbose(void)
|
|||||||
{
|
{
|
||||||
global_verbosity_state = true;
|
global_verbosity_state = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool reporting_get_verbosity(void)
|
||||||
|
{
|
||||||
|
return global_verbosity_state;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user