Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Last active February 1, 2020 22:13
Show Gist options
  • Save lighth7015/64209131b8c489a7e2ef93713d93e191 to your computer and use it in GitHub Desktop.
Save lighth7015/64209131b8c489a7e2ef93713d93e191 to your computer and use it in GitHub Desktop.
ELF loader
#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