From 349ef4460afd0af26a1389c60ac802c335c279af Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 4 Jul 2025 15:36:43 +0100 Subject: [PATCH] exe: implement querying of executable metadata from simple elf executables --- src/elf.h | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/exe.c | 79 +++++++++++++++ src/exe.h | 13 +++ 3 files changed, 376 insertions(+) create mode 100644 src/elf.h create mode 100644 src/exe.c create mode 100644 src/exe.h diff --git a/src/elf.h b/src/elf.h new file mode 100644 index 0000000..9f1358b --- /dev/null +++ b/src/elf.h @@ -0,0 +1,284 @@ +#ifndef ELF_H_ +#define ELF_H_ + +#include +#include + +#define ELF_MAG0 0x7f +#define ELF_MAG1 'E' +#define ELF_MAG2 'L' +#define ELF_MAG3 'F' +#define ELF_NIDENT 16 + +#define SHT_NONE 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_DYNAMIC 6 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_DYNSYM 11 + +/** Little endian. */ +#define ELFDATA2LSB (1) + +/** 64-bit. */ +#define ELFCLASS64 (2) + +#define EM_386 (3) +#define EM_X86_64 (62) + +/** ELF current version. */ +#define EV_CURRENT (1) + +/** Dynamic section tags. */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_JMPREL 23 +#define DT_GNU_HASH 0x6ffffef5 +#define DT_AUXILIARY 0x7ffffffd + +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_GOT32X 43 + +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +/* Section flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 + +#define SHN_UNDEF 0 + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((elf_word_t)(i)) +#define ELF64_ST_BIND(i) ((i) >> 4) +#define ELF64_ST_TYPE(i) ((i) & 0xf) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_NUM 3 + +typedef uint64_t elf_addr_t; +typedef uint64_t elf_off_t; +typedef uint16_t elf_half_t; +typedef uint32_t elf_word_t; +typedef int32_t elf_sword_t; +typedef uint64_t elf_xword_t; +typedef int64_t elf_sxword_t; + +/** + * ELF file header. + */ +typedef struct { + uint8_t e_ident[ELF_NIDENT]; + elf_half_t e_type; + elf_half_t e_machine; + elf_word_t e_version; + elf_addr_t e_entry; + elf_off_t e_phoff; + elf_off_t e_shoff; + elf_word_t e_flags; + elf_half_t e_ehsize; + elf_half_t e_phentsize; + elf_half_t e_phnum; + elf_half_t e_shentsize; + elf_half_t e_shnum; + elf_half_t e_shstrndx; +} elf_ehdr_t; + +/** + * ELF section header. + */ +typedef struct { + elf_word_t sh_name; + elf_word_t sh_type; + elf_xword_t sh_flags; + elf_addr_t sh_addr; + elf_off_t sh_offset; + elf_xword_t sh_size; + elf_word_t sh_link; + elf_word_t sh_info; + elf_xword_t sh_addralign; + elf_xword_t sh_entsize; +} elf_shdr_t; + +/** + * ELF symbol. + */ +typedef struct { + elf_word_t st_name; + unsigned char st_info; + unsigned char st_other; + elf_half_t st_shndx; + elf_addr_t st_value; + elf_xword_t st_size; +} elf_sym_t; + +/** + * ELF program header. + */ +typedef struct { + elf_word_t p_type; + elf_word_t p_flags; + elf_off_t p_offset; + elf_addr_t p_vaddr; + elf_addr_t p_paddr; + elf_xword_t p_filesz; + elf_xword_t p_memsz; + elf_xword_t p_align; +} elf_phdr_t; + +/** + * Extended ELF relocation information. + */ +typedef struct { + elf_addr_t r_offset; + elf_xword_t r_info; + elf_sxword_t r_addend; +} elf_rela_t; + +/** + * Dynamic section entries + */ +typedef struct { + elf_sxword_t d_tag; + union { + elf_xword_t d_val; + elf_addr_t d_ptr; + } d_un; +} elf_dyn_t; + +/** + * Section header types. + */ +enum elf_stype { + ST_NONE = 0, + ST_PROGBITS = 1, + ST_SYMTAB = 2, + ST_STRTAB = 3, + ST_NOBITS = 8, + ST_REL = 9 +}; + +/** + * Program header types. + */ +enum elf_ptype { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, +}; + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 + +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +/** + * ELF identification byte locations. + */ +enum elf_ident { + EI_MAG0 = 0, + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, + EI_DATA = 5, + EI_VERSION = 6, + EI_OSABI = 7, + EI_ABIVERSION = 8, + EI_PAD = 9 +}; + +enum elf_type { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, +}; + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 +#define AT_CLKTCK 17 +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_FPUCW 18 +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +#define AT_IGNOREPPC 22 +#define AT_SECURE 23 +#define AT_BASE_PLATFORM 24 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_EXECFN 31 +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 +#define AT_ENTRY_COUNT 38 + +#endif diff --git a/src/exe.c b/src/exe.c new file mode 100644 index 0000000..16b726b --- /dev/null +++ b/src/exe.c @@ -0,0 +1,79 @@ +#include "exe.h" + +#include "elf.h" + +static enum ec3_status get_elf_executable_info( + FILE *fp, + struct ec3_tag_executable_info *out) +{ + elf_ehdr_t hdr; + fseek(fp, 0, SEEK_SET); + size_t r = fread(&hdr, sizeof hdr, 1, fp); + if (r != 1) { + return EC3_ERR_IO_FAILURE; + } + + out->exe_elf.elf_entry = hdr.e_entry; + + bool text_found = false, data_found = false; + + for (size_t i = 0; i < hdr.e_phnum; i++) { + elf_phdr_t phdr; + size_t offset = hdr.e_phoff + (i * hdr.e_phentsize); + fseek(fp, offset, SEEK_SET); + r = fread(&phdr, sizeof phdr, 1, fp); + + if (r != 1) { + return EC3_ERR_IO_FAILURE; + } + + if (phdr.p_type != PT_LOAD) { + continue; + } + + if ((phdr.p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) { + if (text_found) { + out->exe_format = EC3_EXEC_OTHER; + return EC3_SUCCESS; + } + + out->exe_elf.elf_text_offset = phdr.p_offset; + out->exe_elf.elf_text_filesz = phdr.p_filesz; + out->exe_elf.elf_text_vaddr = phdr.p_vaddr; + out->exe_elf.elf_text_memsz = phdr.p_memsz; + out->exe_elf.elf_text_align = phdr.p_align; + text_found = true; + } + + if ((phdr.p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) { + if (data_found) { + out->exe_format = EC3_EXEC_OTHER; + return EC3_SUCCESS; + } + + out->exe_elf.elf_data_offset = phdr.p_offset; + out->exe_elf.elf_data_filesz = phdr.p_filesz; + out->exe_elf.elf_data_vaddr = phdr.p_vaddr; + out->exe_elf.elf_data_memsz = phdr.p_memsz; + out->exe_elf.elf_data_align = phdr.p_align; + data_found = true; + } + } + + return EC3_SUCCESS; +} + +enum ec3_status get_executable_info_from_file( + FILE *fp, + enum ec3_executable_format format, + struct ec3_tag_executable_info *out) +{ + out->exe_format = format; + + switch (format) { + case EC3_EXEC_ELF: + return get_elf_executable_info(fp, out); + default: + return EC3_SUCCESS; + } +} diff --git a/src/exe.h b/src/exe.h new file mode 100644 index 0000000..904a13a --- /dev/null +++ b/src/exe.h @@ -0,0 +1,13 @@ +#ifndef EXE_H_ +#define EXE_H_ + +#include "tag.h" + +#include + +extern enum ec3_status get_executable_info_from_file( + FILE *fp, + enum ec3_executable_format format, + struct ec3_tag_executable_info *out); + +#endif