Skip to content

Instantly share code, notes, and snippets.

@fherbine
Created October 20, 2022 14:44
Show Gist options
  • Save fherbine/c8475ec9908f1b45ceab1f26d14c257e to your computer and use it in GitHub Desktop.
Save fherbine/c8475ec9908f1b45ceab1f26d14c257e to your computer and use it in GitHub Desktop.
POC for 42 subject: nm
/* 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