Created
October 20, 2022 14:44
-
-
Save fherbine/c8475ec9908f1b45ceab1f26d14c257e to your computer and use it in GitHub Desktop.
POC for 42 subject: nm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* exit */ | |
#include <stdlib.h> | |
/* close, fstat */ | |
#include <unistd.h> | |
/* open, fstat */ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
/* mmap, munmap */ | |
#include <sys/mman.h> | |
/* uint defines */ | |
#include <stdint.h> | |
/* elf */ | |
#include <elf.h> | |
/* Subject forbidden funcs !!! */ | |
/* printf */ | |
#include <stdio.h> | |
/* toupper */ | |
#include <ctype.h> | |
/* strcmp */ | |
# include <string.h> | |
/** Inspired from https://wiki.osdev.org/ELF_Tutorial **/ | |
static inline Elf64_Shdr *elf_sheader(void *hdr) { | |
return (Elf64_Shdr *)(hdr + ((Elf64_Ehdr *)hdr)->e_shoff); | |
} | |
static inline Elf64_Shdr *get_elf_section(void *hdr, int idx) { | |
return &elf_sheader(hdr)[idx]; | |
} | |
static inline char *elf_str_table(void *hdr) { | |
if(((Elf64_Ehdr *)hdr)->e_shstrndx == SHN_UNDEF) return NULL; | |
return (char *)hdr + get_elf_section(hdr, ((Elf64_Ehdr *)hdr)->e_shstrndx)->sh_offset; | |
} | |
static inline char *elf_lookup_string(void *hdr, int offset) { | |
char *strtab = elf_str_table(hdr); | |
if(strtab == NULL) return NULL; | |
return (char *)(strtab + offset); | |
} | |
/* | |
static int elf_get_symval(Elf32_Ehdr *hdr, int table, uint64_t idx) { | |
if(table == SHN_UNDEF || idx == SHN_UNDEF) return 0; | |
Elf32_Shdr *symtab = elf_section(hdr, table); | |
uint32_t symtab_entries = symtab->sh_size / symtab->sh_entsize; | |
if(idx >= symtab_entries) { | |
dprintf(STDERR_FILENO ,"Symbol Index out of Range (%d:%u).\n", table, idx); | |
return -1; | |
} | |
int symaddr = (int)hdr + symtab->sh_offset; | |
Elf32_Sym *symbol = &((Elf32_Sym *)symaddr)[idx]; | |
if(symbol->st_shndx == SHN_UNDEF) { | |
// External symbol, lookup value | |
Elf32_Shdr *strtab = elf_section(hdr, symtab->sh_link); | |
const char *name = (const char *)hdr + strtab->sh_offset + symbol->st_name; | |
extern void *elf_lookup_symbol(const char *name); | |
void *target = elf_lookup_symbol(name); | |
if(target == NULL) { | |
// Extern symbol not found | |
if(ELF32_ST_BIND(symbol->st_info) & STB_WEAK) { | |
// Weak symbol initialized as 0 | |
return 0; | |
} else { | |
dprintf(STDERR_FILENO, "Undefined External Symbol : %s.\n", name); | |
return -1; | |
} | |
} else { | |
return (int)target; | |
} | |
} else if(symbol->st_shndx == SHN_ABS) { | |
// Absolute symbol | |
return symbol->st_value; | |
} else { | |
// Internally defined symbol | |
Elf32_Shdr *target = elf_section(hdr, symbol->st_shndx); | |
return (int)hdr + symbol->st_value + target->sh_offset; | |
} | |
} */ | |
/********************************************************/ | |
Elf64_Shdr *get_symtab_section_elf64(void *ptr) { | |
Elf64_Ehdr header; | |
header = *(Elf64_Ehdr *)ptr; | |
if (!header.e_shoff) { | |
return NULL; | |
} | |
for (int i = 0; i < header.e_shnum; i++) | |
{ | |
Elf64_Shdr *section_header = get_elf_section(ptr, i); | |
if (section_header->sh_type == SHT_SYMTAB) | |
return section_header; | |
} | |
return NULL; | |
} | |
Elf64_Sym *get_symbol(void *ptr, uint64_t idx) { | |
Elf64_Shdr *symtab_section = get_symtab_section_elf64(ptr); | |
uint64_t symtab_entries = symtab_section->sh_size / symtab_section->sh_entsize; | |
if(idx >= symtab_entries) { | |
dprintf(STDERR_FILENO ,"Symbol Index out of Range (%lu).\n", idx); | |
return NULL; | |
} | |
void *symaddr = ptr + symtab_section->sh_offset; | |
return &(((Elf64_Sym *)symaddr)[idx]); | |
} | |
static inline char *elf_lookup_symbol_string(void *ptr, uint64_t idx) { | |
Elf64_Shdr *symtab = get_symtab_section_elf64(ptr); | |
Elf64_Sym *symbol = get_symbol(ptr, idx); | |
Elf64_Shdr *strtab = get_elf_section(ptr, symtab->sh_link); | |
return ptr + strtab->sh_offset + symbol->st_name; | |
} | |
static inline char *get_section_name_by_shidx(void *ptr, int idx) { | |
Elf64_Shdr *section_header = get_elf_section(ptr, idx); | |
return (section_header->sh_name == SHN_UNDEF) ? "NULL" : elf_lookup_string( | |
ptr, section_header->sh_name | |
); | |
} | |
uint8_t is_elf64_is_stripped(void *ptr) { | |
return (get_symtab_section_elf64(ptr) == NULL) ? 1 : 0; | |
} | |
char get_nm_symtype(void *ptr, Elf64_Sym *symbol) { | |
char sym = 0; | |
if (symbol->st_shndx == SHN_UNDEF) | |
return 'U'; | |
if (symbol->st_shndx == SHN_ABS) | |
return 'A'; | |
Elf64_Shdr *sym_section = get_elf_section(ptr, symbol->st_shndx); | |
char *section_name = elf_lookup_string(ptr, sym_section->sh_name); | |
//printf("%s", section_name); | |
if (!(sym_section->sh_flags & SHF_WRITE)) | |
sym ='r'; | |
if (!strcmp(section_name, ".bss")) | |
sym = 'b'; | |
else if (!strcmp(section_name, ".text")) | |
sym = 't'; | |
else if ( | |
!strcmp(section_name, ".data") | |
|| !strcmp(section_name, ".data1") | |
|| !strcmp(section_name, ".dynamic") | |
|| !strcmp(section_name, ".fini_array") | |
|| !strcmp(section_name, ".got") | |
|| !strcmp(section_name, ".init_array") | |
) | |
sym = 'd'; | |
else if (!strcmp(section_name, ".rodata") || !strcmp(section_name, ".rodata1")) | |
sym = 'r'; | |
if (ELF64_ST_BIND(symbol->st_info) == STB_WEAK) | |
sym = (symbol->st_value)? 'W' : 'w'; | |
return (ELF64_ST_BIND(symbol->st_info) == STB_GLOBAL) ? toupper(sym) : sym; | |
} | |
uint8_t read_shdr(Elf64_Shdr *section_header, void *ptr) { | |
if (section_header->sh_name != SHN_UNDEF) | |
printf("Name: %20s\t", elf_lookup_string(ptr, section_header->sh_name)); | |
else | |
printf("Name: %20s\t", "NULL"); | |
printf("Type: "); | |
switch (section_header->sh_type) | |
{ | |
case SHT_NULL: | |
printf("SHT_NULL\t"); | |
break; | |
case SHT_PROGBITS: | |
printf("SHT_PROGBITS\t"); | |
break; | |
case SHT_SYMTAB: | |
printf("SHT_SYMTAB\t"); | |
break; | |
case SHT_STRTAB: | |
printf("SHT_STRTAB\t"); | |
break; | |
case SHT_RELA: | |
printf("SHT_RELA\t"); | |
break; | |
case SHT_HASH: | |
printf("SHT_HASH\t"); | |
break; | |
default: | |
printf("OTHER\t"); | |
break; | |
} | |
printf("Size: %#lx\n", section_header->sh_size); | |
if (section_header->sh_type == SHT_SYMTAB) { | |
for (int i = 0; i < (get_symtab_section_elf64(ptr)->sh_size / sizeof(Elf64_Sym)); i++) | |
{ | |
Elf64_Sym *symbol = get_symbol(ptr, i); | |
if (symbol->st_name == 0x0) | |
continue ; | |
/* Types to ignore */ | |
if (ELF64_ST_TYPE(symbol->st_info) == STT_FILE) | |
continue ; | |
if (symbol->st_value) | |
printf("%016lx ", symbol->st_value); | |
else | |
printf("%18s", " "); | |
switch (symbol->st_shndx) | |
{ | |
case SHN_UNDEF: | |
printf("UND "); | |
break; | |
case SHN_ABS: | |
printf("ABS "); | |
break; | |
default: | |
printf("%3d ", (uint16_t)symbol->st_shndx); | |
break; | |
} | |
printf("%c ", get_nm_symtype(ptr, symbol)); | |
printf("%s\n", elf_lookup_symbol_string(ptr, i)); | |
} | |
} | |
return (1); | |
} | |
void handle_elf64(void *ptr) { | |
Elf64_Ehdr header; | |
header = *(Elf64_Ehdr *)ptr; | |
if (!header.e_phoff) { | |
printf("No program header table.\n"); | |
return ; | |
} | |
if (!header.e_shoff) { | |
printf("No section header table.\n"); | |
return ; | |
} | |
if (is_elf64_is_stripped(ptr)) { | |
dprintf(STDERR_FILENO, "ft_nm: <filename>: no symbol.\n"); | |
exit(EXIT_FAILURE); | |
} | |
for (int i = 0; i < header.e_shnum; i++) | |
{ | |
printf("[%2d] ", i); | |
read_shdr(get_elf_section(ptr, i), ptr); | |
} | |
} | |
void nm(void *ptr) { | |
uint32_t magic_number; | |
uint8_t elf_class; | |
magic_number = *(uint32_t *)ptr; | |
if (magic_number == *(uint32_t *)ELFMAG) { | |
printf("This file is ELF.\n"); | |
elf_class = *(uint8_t *)(ptr + EI_CLASS); | |
if (elf_class == ELFCLASS32) { | |
printf("32bits\n"); | |
} else if (elf_class == ELFCLASS64) { | |
printf("64bits\n"); | |
handle_elf64(ptr); | |
} | |
} | |
} | |
int main(int argc, char **argv) { | |
int fd; | |
void *ptr; | |
struct stat buf; | |
if (argc != 2) { | |
dprintf(STDERR_FILENO, "Too many/few arguments.\n"); | |
exit(EXIT_FAILURE); | |
} | |
if ((fd = open(argv[1], O_RDONLY)) < 0) { | |
perror("open"); | |
exit(EXIT_FAILURE); | |
} | |
if (fstat(fd, &buf) < 0) { | |
perror("fstat"); | |
exit(EXIT_FAILURE); | |
} | |
if ((ptr = mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { | |
perror("mmap"); | |
exit(EXIT_FAILURE); | |
} | |
nm(ptr); | |
if (munmap(ptr, buf.st_size) < 0) { | |
perror("munmap"); | |
exit(EXIT_FAILURE); | |
} | |
close(fd); | |
return (EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment