Last active
February 1, 2020 22:13
-
-
Save lighth7015/64209131b8c489a7e2ef93713d93e191 to your computer and use it in GitHub Desktop.
ELF loader
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
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <libelf.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <dlfcn.h> | |
#include <fcntl.h> | |
// I'm.. going to leave this in because I will use it later. | |
int is_image_valid(Elf32_Ehdr *hdr) { | |
return 1; | |
} | |
// Thunk: libc <--/ Server / <-- Client | |
void *resolve(const char* sym) { | |
static void *handle = NULL; | |
if (handle == NULL) { | |
handle = dlopen("libc.so", RTLD_NOW); | |
} | |
return dlsym(handle, sym); | |
} | |
void relocate(Elf32_Shdr* section, const Elf32_Sym* syms, const char* strings, const char* src, char* dst) { | |
Elf32_Rel* rel = (Elf32_Rel*)(src + section->sh_offset); | |
int j; | |
for(j = 0; j < section->sh_size / sizeof(Elf32_Rel); j += 1) { | |
const char* sym = strings + syms[ELF32_R_SYM(rel[j].r_info)].st_name; | |
switch(ELF32_R_TYPE(rel[j].r_info)) { | |
case R_386_JMP_SLOT: | |
case R_386_GLOB_DAT: | |
// CRASH: Somehow, this target dereference apparently the Section points to 0xc. | |
*(Elf32_Word*)(dst + rel[j].r_offset) = (Elf32_Word)resolve(sym); | |
break; | |
} | |
} | |
} | |
void* find_sym(const char* name, Elf32_Shdr* shdr, const char* strings, const char* src, char* dst) { | |
Elf32_Sym* syms = (Elf32_Sym*)(src + shdr->sh_offset); | |
void* address = NULL; | |
for(int i = 0; i < shdr->sh_size / sizeof(Elf32_Sym); i += 1) { | |
if (strcmp(name, strings + syms[i].st_name) == 0) { | |
address = dst + syms[i].st_value; | |
goto finished; | |
} | |
} | |
finished: | |
return address; | |
} | |
void *image_load ( const char* filename, const char* symbol ) { | |
int fd = -1, flags = PROT_READ | PROT_WRITE | PROT_EXEC; | |
char* buffer = NULL; | |
struct stat fileInfo; | |
if (( fd = open(filename, O_RDONLY )) < 0 | |
|| (fstat( fd, &fileInfo )) < 0) { | |
puts("Unable to stat file."); | |
} | |
else if (( buffer = calloc( 1, fileInfo.st_size )) != NULL) { | |
read( fd, buffer, fileInfo.st_size ); | |
Elf32_Ehdr *image = (Elf32_Ehdr *) buffer; | |
intptr_t address = -1; | |
if(is_image_valid(image)) { | |
char *mapped = NULL; | |
if ((mapped = mmap( NULL, fileInfo.st_size, flags, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0))) { | |
printf("Mapped image to address %p-%08lx.\n", (intptr_t *) mapped, ((intptr_t) mapped) + fileInfo.st_size); | |
Elf32_Phdr *program = (Elf32_Phdr *)(buffer + image->e_phoff); | |
printf("Image file has %d sections.\n", image->e_phnum ); | |
for(int i=0; i < image->e_phnum; ++i) { | |
if(program[i].p_type == PT_LOAD) { | |
if(program[i].p_filesz > program[i].p_memsz) { | |
printf("image_load:: p_filesz > p_memsz\n"); | |
munmap(mapped, fileInfo.st_size); | |
return 0; | |
} | |
// p_filesz can be smaller than p_memsz, the difference is zeroe'd out. | |
else if(program[i].p_filesz) { | |
char* start = buffer + program[i].p_offset, | |
* taddr = program[i].p_vaddr + buffer; | |
memmove(taddr,start,program[i].p_filesz); | |
// Read-only. | |
if(!(program[i].p_flags & PF_W)) { | |
mprotect((intptr_t *) taddr, program[i].p_memsz, PROT_READ); | |
} | |
// Executable. | |
if(program[i].p_flags & PF_X) { | |
mprotect((intptr_t *) taddr, program[i].p_memsz, PROT_EXEC); | |
} | |
} | |
} | |
} | |
Elf32_Shdr *section = (Elf32_Shdr *) (buffer + image->e_shoff); | |
Elf32_Sym *symbols = NULL; | |
char* strings = NULL; | |
for(int i=0; i < image->e_shnum; ++i) { | |
switch (section[i].sh_type) { | |
case SHT_DYNSYM: | |
case SHT_SYMTAB: | |
symbols = (Elf32_Sym *)(buffer + section[i].sh_offset); | |
strings = buffer + section[section[i].sh_link].sh_offset; | |
if (( address = (intptr_t) find_sym(symbol, section + i, strings, buffer, mapped))) { | |
printf("%-16s Found symbol, address = 0x%08x.\n", symbol, (intptr_t) section); | |
goto try_relocate; | |
} | |
} | |
} | |
try_relocate: | |
for(int i=0; i < image->e_shnum; ++i) { | |
if (section[i].sh_type == SHT_REL) { | |
relocate(section + i, symbols, strings, buffer, mapped); | |
} | |
} | |
return (void *) address; | |
} | |
else { | |
puts("Unable to map image."); | |
} | |
} | |
else { | |
printf("%s: Not an executable image.\n", filename); | |
} | |
} | |
return 0; | |
}/* image_load */ | |
int main(int args, char** arg, char** envp) { | |
int (*proc)(int, char **, char**); | |
if (args >= 2) { | |
if (( proc = image_load( arg[1], "main" ))) { | |
printf("Located symbol, address=0x%08x.\n", (intptr_t) proc); | |
return proc(args, arg, envp); | |
} | |
else { | |
printf("Unable to execute image, address=0x%08x.\n", (intptr_t) proc); | |
} | |
} | |
else { | |
puts("Usage: loadelf32 [filename[, entry-point]]"); | |
} | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment